Skip to content

fix(astro): normalize file URL paths on Windows#67

Open
mhanelia wants to merge 1 commit into
multivmlabs:mainfrom
mhanelia:fix-astro-windows-file-url-paths
Open

fix(astro): normalize file URL paths on Windows#67
mhanelia wants to merge 1 commit into
multivmlabs:mainfrom
mhanelia:fix-astro-windows-file-url-paths

Conversation

@mhanelia

Copy link
Copy Markdown
Contributor

Summary

Fixes Windows path handling in the Astro integration when Astro provides publicDir and outDir as file:// URLs.

What changed

Converted Astro file:// URLs to native filesystem paths using Node's fileURLToPath().

Updated dev publicDir creation to use the normalized filesystem path.

Updated build output scanning to normalize the Astro build output URL before reading generated HTML.

Added a regression test with mocked Windows publicDir and outDir file URLs.

Why

On Windows, using URL.pathname directly can produce paths like /C:/Users/....
Captura de tela 2026-06-10 132959

When passed to filesystem APIs, this can be interpreted incorrectly and result in duplicated drive paths like C:\C:\Users\...\public.

Using fileURLToPath() preserves correct behavior across Windows, Linux, and macOS.

Validation

npx.cmd tsc --noEmit

npm.cmd run build

npx.cmd vitest run src/plugins/astro.test.ts

npx.cmd vitest run ⚠️ 1 unrelated pre-existing failure in src/plugins/angular.test.ts (should scan Angular routes from source)

@vercel

vercel Bot commented Jun 10, 2026

Copy link
Copy Markdown

@mhanelia is attempting to deploy a commit to the Cytonic Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes Windows path handling in the Astro integration by replacing direct .pathname accesses on URL objects with a new toFileSystemPath helper that uses Node's fileURLToPath(), preventing the duplicated drive-letter paths (C:\C:\...) that occur when URL.pathname is passed directly to filesystem APIs on Windows.

  • Introduces toFileSystemPath(pathOrUrl: string | URL) which delegates to fileURLToPath for URL instances and applies a drive-letter-stripping regex for strings that are already URL pathnames.
  • Updates three call sites in astro:config:setup and astro:build:done to use the new helper instead of .pathname.
  • Adds a vitest regression test that mocks Windows file:// URLs and verifies mkdirSync is called with the correctly normalized path.

Confidence Score: 4/5

Safe to merge — the core fix is correct and the changed call sites all receive Astro's guaranteed file: URL objects.

The toFileSystemPath helper correctly handles both URL objects (via fileURLToPath) and string pathnames (via the drive-letter regex). The three replaced .pathname accesses are the right fix for the Windows bug. The only gaps are that the new test does not exercise the build command paths or the astro:build:done hook, and the helper type signature does not guard against non-file: URLs — both are unlikely to matter given Astro internals but worth tightening.

No files require special attention; both changed files are straightforward. The test file could benefit from additional coverage of the build-command paths.

Important Files Changed

Filename Overview
src/plugins/astro.ts Adds toFileSystemPath helper using fileURLToPath and a Windows-pathname regex; replaces three direct .pathname accesses. Logic is correct for Astro's guaranteed file: URLs; minor concern that the helper will throw for non-file: URL inputs.
src/plugins/astro.test.ts New regression test using a mocked Windows file:// URL; only covers the dev command mkdirSync call — the build config path and astro:build:done hook are untested.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["astro:config:setup\n(config.publicDir / config.outDir)"] --> B{toFileSystemPath}
    C["astro:build:done\n(dir || astroConfig.outDir)"] --> B
    B --> D{pathOrUrl instanceof URL?}
    D -- Yes --> E["fileURLToPath(pathOrUrl)\n→ correct OS path"]
    D -- No --> F["regex: strip leading /C: prefix\n→ correct OS path"]
    E --> G["Use in fs.mkdirSync /\nresolveConfig / scanBuiltPages"]
    F --> G
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
src/plugins/astro.test.ts:16-31
**Limited test coverage for the fix**

The test only exercises the `dev` command path (checking `mkdirSync`). The same `toFileSystemPath` helper is also called in the `build` branch of `astro:config:setup` (`toFileSystemPath(config.outDir)`) and in the `astro:build:done` hook (`toFileSystemPath(dir || astroConfig.outDir)`). A Windows `file://` URL passed as `dir` in the build hook — the original crash site described in the PR — is not covered by any test here, so a future refactor could re-introduce the regression without failing CI.

### Issue 2 of 2
src/plugins/astro.ts:100-106
**String-branch regex is silently skipped for non-`file:` URLs**

When `pathOrUrl` is a `URL` whose protocol is not `file:` (e.g. `http:` or `https:`), `fileURLToPath` will throw a `TypeError: The URL must be of scheme file`. Astro guarantees `file:` URLs for `publicDir`, `outDir`, and the build `dir` parameter, so this won't trigger today. However, since the helper accepts a generic `string | URL`, callers could inadvertently pass a non-`file:` URL and receive an unhandled exception rather than a graceful error. Narrowing the accepted type or adding a protocol guard would make the contract explicit.

Reviews (1): Last reviewed commit: "fix(astro): normalize file URL paths on ..." | Re-trigger Greptile

Comment thread src/plugins/astro.test.ts
Comment on lines +16 to +31
describe('aeoAstroIntegration', () => {
it('uses native filesystem paths for Astro file URLs in dev', () => {
fsMocks.existsSync.mockReturnValue(false);

const publicDir = new URL('file:///C:/mock/project/public');
const outDir = new URL('file:///C:/mock/project/dist');
const integration = aeoAstroIntegration({ widget: { enabled: false } });

integration.hooks['astro:config:setup']({
config: { publicDir, outDir },
command: 'dev',
});

expect(fsMocks.mkdirSync).toHaveBeenCalledWith(fileURLToPath(publicDir), { recursive: true });
});
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Limited test coverage for the fix

The test only exercises the dev command path (checking mkdirSync). The same toFileSystemPath helper is also called in the build branch of astro:config:setup (toFileSystemPath(config.outDir)) and in the astro:build:done hook (toFileSystemPath(dir || astroConfig.outDir)). A Windows file:// URL passed as dir in the build hook — the original crash site described in the PR — is not covered by any test here, so a future refactor could re-introduce the regression without failing CI.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugins/astro.test.ts
Line: 16-31

Comment:
**Limited test coverage for the fix**

The test only exercises the `dev` command path (checking `mkdirSync`). The same `toFileSystemPath` helper is also called in the `build` branch of `astro:config:setup` (`toFileSystemPath(config.outDir)`) and in the `astro:build:done` hook (`toFileSystemPath(dir || astroConfig.outDir)`). A Windows `file://` URL passed as `dir` in the build hook — the original crash site described in the PR — is not covered by any test here, so a future refactor could re-introduce the regression without failing CI.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread src/plugins/astro.ts
Comment on lines +100 to +106
function toFileSystemPath(pathOrUrl: string | URL): string {
if (pathOrUrl instanceof URL) {
return fileURLToPath(pathOrUrl);
}

return pathOrUrl.replace(/^\/([A-Za-z]:)(?=\/|\\)/, '$1');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 String-branch regex is silently skipped for non-file: URLs

When pathOrUrl is a URL whose protocol is not file: (e.g. http: or https:), fileURLToPath will throw a TypeError: The URL must be of scheme file. Astro guarantees file: URLs for publicDir, outDir, and the build dir parameter, so this won't trigger today. However, since the helper accepts a generic string | URL, callers could inadvertently pass a non-file: URL and receive an unhandled exception rather than a graceful error. Narrowing the accepted type or adding a protocol guard would make the contract explicit.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugins/astro.ts
Line: 100-106

Comment:
**String-branch regex is silently skipped for non-`file:` URLs**

When `pathOrUrl` is a `URL` whose protocol is not `file:` (e.g. `http:` or `https:`), `fileURLToPath` will throw a `TypeError: The URL must be of scheme file`. Astro guarantees `file:` URLs for `publicDir`, `outDir`, and the build `dir` parameter, so this won't trigger today. However, since the helper accepts a generic `string | URL`, callers could inadvertently pass a non-`file:` URL and receive an unhandled exception rather than a graceful error. Narrowing the accepted type or adding a protocol guard would make the contract explicit.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant