Skip to content

Fix NodePath file URL conversion to follow the layer's platform flavor - #6914

Merged
tim-smart merged 4 commits into
Effect-TS:mainfrom
spencerbeggs:fix/node-path-flavored-file-urls
Aug 3, 2026
Merged

Fix NodePath file URL conversion to follow the layer's platform flavor#6914
tim-smart merged 4 commits into
Effect-TS:mainfrom
spencerbeggs:fix/node-path-flavored-file-urls

Conversation

@spencerbeggs

@spencerbeggs spencerbeggs commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Closes #6913.

NodePath built fromFileUrl / toFileUrl once from node:url's host-dependent defaults and spread that same pair into all three layers, so layerWin32 disagreed with itself off Windows: join / dirname / sep were win32 while URL conversion stayed POSIX. layerPosix had the mirror defect on a Windows host.

node:url has exposed the flavor as an option since v22.1.0, so this threads it through rather than reimplementing the conversion: fileUrlOps(false) for layerPosix, fileUrlOps(true) for layerWin32, and fileUrlOps(undefined) for layer, which resolves to the host default and leaves the host layer's behavior unchanged.

The new test mirrors the existing packages/platform-deno/test/DenoPath.test.ts file-URL tests, which already assert this for DenoPath.layerPosix / layerWin32. Before the change the Windows case failed on darwin with expected '/C:/Users/me/file.txt' to equal 'C:\Users\me\file.txt'.

Two things worth a maintainer's judgement:

  • packages/platform-node-shared/package.json declares engines.node: ">=18.0.0", and on Node < 22.1 the extra options argument is silently ignored, so both fixed-flavor layers fall back to host behavior there. That is no worse than today, but it is not fixed either. Since Node 18 and 20 are both EOL, bumping engines seems more honest than vendoring a parallel copy of Node's conversion logic, but I did not want to make that call in this PR.
  • The POSIX half of the new test is vacuous on a POSIX host, where { windows: false } and the host agree, and this repo's CI is ubuntu-only (runs-on: ubuntu-latest across the whole shard/runtime matrix). So nothing here exercises the layerPosix-on-Windows case, and I have no Windows host to check it on either; that half of the fix is reasoned from node:url's platform branch rather than measured. The win32 half is what actually demonstrates the change, and it runs everywhere.

Validation run locally on Node 26.5.0 / darwin: pnpm lint-fix, pnpm check, vitest run --project @effect/platform-node-shared (106 passed), vitest run --project @effect/platform-node (277 passed). One run of the shared suite hit a pre-existing flake in NodeStream.test.ts (PassThrough.onEnd, src/NodeStream.ts:354) that did not reproduce across three subsequent runs and is unrelated to this change.

Signed-off-by: C. Spencer Beggs spencer@beggs.codes

layerPosix and layerWin32 both built fromFileUrl and toFileUrl from node:url's host-dependent defaults, so off Windows layerWin32 returned POSIX file URLs while the rest of the layer used win32 semantics. Both fixed-flavor layers now pass the windows option through to node:url, and layer keeps the host default.

Closes Effect-TS#6913
Signed-off-by: C. Spencer Beggs <spencer@beggs.codes>
@github-project-automation github-project-automation Bot moved this to Discussion Ongoing in PR Backlog Aug 3, 2026
@changeset-bot

changeset-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 15d6a3b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 30 packages
Name Type
@effect/platform-node-shared Patch
effect Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-deno Patch
@effect/platform-node Patch
@effect/vitest Patch
@effect/ai-anthropic Patch
@effect/ai-openai-compat Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/docgen Patch
@effect/doctest Patch
@effect/openapi-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • fileUrlOps factory: Replaced the top-level fromFileUrl/toFileUrl constants with a fileUrlOps(windows) factory that threads the platform flavor through to node:url's fileURLToPath/pathToFileURL. layerPosixfileUrlOps(false), layerWin32fileUrlOps(true), layerfileUrlOps(undefined).
  • New tests: Mirror the Deno path file-URL tests. The Windows test exercises the actual fix — fileURLToPath with { windows: true } correctly returns backslash paths on a POSIX host. Both assertions use strictEqual.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) (Kimi K2 not used — the program covers this model; add its provider key to run your pick) | 𝕏

@spencerbeggs

Copy link
Copy Markdown
Contributor Author

So, this is my fix for the issue. There are some failing tests in the Node layer, but those don't seem to be possibly related to my changes. I think they are test timeouts. Let me know what you think and if you would like any changes.

@spencerbeggs

spencerbeggs commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Note on the one red check, so it does not cost a reviewer time.

Test (1/2, Node) fails in this job on packages/effect/test/cluster/ClusterWorkflowEngine.test.tsWorkflow.withCompensation runs compensation when the workflow fails and Activity.raceAll returns the first activity and interrupts losers, both reporting Test timed out in 5000ms. 181 test files passed, that one failed.

It is not reachable from this diff. The test imports only from effect core, and the effect package has no dependency on @effect/platform-node-shared — the dependency runs the other way. The file also passes locally on this branch, 13/13.

The change itself did get exercised: Test (2/2, Node) ran the new file and passed.

✓  @effect/platform-node-shared  test/NodePath.test.ts (2 tests) 11ms

For what it is worth, the same base commit (8f9499f56) went fully green on #6917, and recent runs across other branches have failed on a different unrelated test most times — DenoFileSystem, HashRing, NumberBindingRepro, sql-mysql2 Persistence.

I can push an empty commit to re-roll it if that is useful, but I did not want to spend a CI run on cosmetics without asking.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
basic.ts 7.06 KB 7.06 KB 0.00 KB (0.00%)
batching.ts 9.86 KB 9.86 KB 0.00 KB (0.00%)
brand.ts 6.34 KB 6.34 KB 0.00 KB (0.00%)
cache.ts 10.62 KB 10.62 KB 0.00 KB (0.00%)
config.ts 20.60 KB 20.60 KB 0.00 KB (0.00%)
differ.ts 20.20 KB 20.20 KB 0.00 KB (0.00%)
http-client.ts 21.49 KB 21.49 KB 0.00 KB (0.00%)
logger.ts 10.76 KB 10.76 KB 0.00 KB (0.00%)
metric.ts 8.98 KB 8.98 KB 0.00 KB (0.00%)
optic.ts 7.18 KB 7.18 KB 0.00 KB (0.00%)
pubsub.ts 14.90 KB 14.90 KB 0.00 KB (0.00%)
queue.ts 11.58 KB 11.58 KB 0.00 KB (0.00%)
schedule.ts 10.74 KB 10.74 KB 0.00 KB (0.00%)
schema-class.ts 19.14 KB 19.14 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 28.96 KB 28.96 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 25.29 KB 25.29 KB 0.00 KB (0.00%)
schema-string-transformation.ts 13.30 KB 13.30 KB 0.00 KB (0.00%)
schema-string.ts 10.94 KB 10.94 KB 0.00 KB (0.00%)
schema-template-literal.ts 15.17 KB 15.17 KB 0.00 KB (0.00%)
schema-toArbitraryLazy.ts 21.94 KB 21.94 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 24.34 KB 24.34 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 19.18 KB 19.18 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 19.01 KB 19.01 KB 0.00 KB (0.00%)
schema-toFormatter.ts 18.87 KB 18.87 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 22.60 KB 22.60 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 19.52 KB 19.52 KB 0.00 KB (0.00%)
schema.ts 18.41 KB 18.41 KB 0.00 KB (0.00%)
stm.ts 12.54 KB 12.54 KB 0.00 KB (0.00%)
stream.ts 9.80 KB 9.80 KB 0.00 KB (0.00%)

@tim-smart

Copy link
Copy Markdown
Contributor

Does deno need updating too?

@spencerbeggs

Copy link
Copy Markdown
Contributor Author

@tim-smart Deno did it the right way (or this way). This just mirrors how Deno works into the @effect/platform-node-shared package with is how Node and Bun use it.

Comment thread .changeset/fix-node-path-file-url-flavor.md Outdated
@tim-smart
tim-smart enabled auto-merge (squash) August 3, 2026 22:48
@tim-smart
tim-smart merged commit 0b4a3c4 into Effect-TS:main Aug 3, 2026
13 of 14 checks passed
@github-project-automation github-project-automation Bot moved this from Discussion Ongoing to Done in PR Backlog Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.0 bug Something isn't working

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

NodePath.layerWin32 / layerPosix use host-platform file URL conversion instead of the layer's flavor

2 participants