Simplify implementation using URL-based resolution#42
Conversation
Replace `path` module with `new URL()` for relative resolution, unifying the path-vs-URL split by normalizing caller refs to `file://` URLs upfront. The `_resolveUrl` helper condenses the previous three-case block into a single ternary; `toCallerUrl` handles both plain paths and `file://` URLs so the public `resolve()` API stays backward-compatible with callers that pass a plain `__filename`. Closes #4 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add JSDoc to all four functions (toCallerUrl, resolveUrl, file, resolve) - Rename _resolveUrl to resolveUrl (remove leading underscore) - Compute isAbsolute, isRelative, isModule before the if/else structure - Restore the three-cases comment in the appropriate place Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Addressed all four review points — all 23 tests still pass:
|
| // 1. absolute path (starts with /) => use as is | ||
| // 2. relative path (starts with ./ or ../) => use URL resolution | ||
| // 3. module path => use require.resolve() for node_modules lookup | ||
| if (isAbsolute) { |
There was a problem hiding this comment.
Does this handle all cases? Is this possible for values to bypass all three if blocks?
…ith else - `callerRef` was vague; `path` is clear — the parameter is a filesystem path or file:// URL, matching how callerPath is named elsewhere - `else if (isModule)` implied a possible gap; since isModule is defined as `!isAbsolute && !isRelative`, the three branches are exhaustive — `else` makes that obvious Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Addressed both new comments — all 23 tests still pass:
|
Closes #4 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Done — moved exported functions before the helpers, relying on hoisting. Structure is now:
All 23 tests still pass. |
| if (callerPath === undefined) { | ||
| callerPath = toFilePath(caller()); | ||
| } | ||
| const callerUrl = toCallerUrl(callerPath !== undefined ? callerPath : caller()); |
There was a problem hiding this comment.
Please handle the ternary in its own assignment statement
There was a problem hiding this comment.
Done — split into const ref = callerPath !== undefined ? callerPath : caller(); on its own line, then const callerUrl = toCallerUrl(ref);.
- Changed `export function file(...)` to `function file(...)` with
explicit `export { file }` so the named export is unambiguous
- Split inline ternary in `resolve()` into its own `ref` variable
before passing to `toCallerUrl()`
Closes #4
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Please assess after this change: What's cleaner? What's simpler? Where is the code easier to read? Where is it more resilient and less error prone? And where is it worse in any of these regards? |
|
Honest assessment of the full diff (branch vs. main): Cleaner / simpler / easier to readFewer imports — dropping
Exhaustive Worse / more fragileMixed return type from
Neutral
SummaryThe URL-space approach is genuinely cleaner overall — fewer imports, no try/catch control flow, simpler relative resolution. The main thing worth fixing before merging: unify |
| } catch { | ||
| return callerUrl; | ||
| return new URL(filePath, callerUrl); | ||
| } else { |
There was a problem hiding this comment.
Put this back to else if (isModule). Otherwise the computed constant is unused and the code becomes less clear in signaling intent.
There was a problem hiding this comment.
Done — the code already has else if (isModule) since the commit at 08:18. I had addressed it in the issue comment but forgot to reply here in the thread. Apologies for the noise.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Done — changed back to |
Can we fix this? Is it better to translate at the boundary of our module?
And this also makes me wonder whether much of the value of the URL type could be enjoyed in a similarly-designed Path type 🤔 |
- toCallerUrl() now returns a URL object instead of a string - resolveUrl() always returns a URL: absolute/relative paths → file://, npm packages → file://, Node built-ins → node:<name> - resolve() converts file: URLs via fileURLToPath, node: URLs via pathname - file() passes URL directly to readFileSync (natively supported) - Eliminates the instanceof URL branch and the mixed string|URL return type Closes #42 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chriscalo
left a comment
There was a problem hiding this comment.
Responded to comments. Not sure if this is necessary to create a review.
|
Done — all 23 tests still pass. Here's what changed:
The On the |
Revert the named-export style from `function file() {}` + `export { file }`
back to the simpler `export function file()` declaration, which already
provides a named export without the extra statement.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| }); | ||
| const callerUrl = toCallerUrl(caller()); | ||
| const resolved = resolveUrl(filePath, callerUrl); | ||
| return readFileSync(resolved, { encoding: "utf-8", ...options }); |
There was a problem hiding this comment.
Handle the options resolution in a separate constant assignment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Done — extracted |
Closes #4
What changed
pathmodule imports (dirname,isAbsolute,resolve) — no longer neededpathToFileURLto normalize plain paths →file://URLstoFilePath()withtoCallerUrl(): instead of converting everything to a plain path, we now work in URL-space throughout_resolveUrl()helper that collapses the previous three-caseif/else if/else ifblock into a single ternarynew URL(filePath, callerUrl)instead ofpath.resolve(dirname(callerPath), ...)createRequirenow receives afile://URL directly (it accepts this natively)What's preserved
callerpackage (noError.stackregex)optionspassthrough infile()createRequireresolve()public API — still accepts a plain filesystem path as the second argument; still returns a plain string pathThe diff is −68/+17 lines, net −51 lines.