Skip to content

Add ForwardSlashPath branded type and forward-slash path utilities#1853

Open
Copilot wants to merge 3 commits intomainfrom
copilot/add-branded-string-utility-function
Open

Add ForwardSlashPath branded type and forward-slash path utilities#1853
Copilot wants to merge 3 commits intomainfrom
copilot/add-branded-string-utility-function

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 14, 2026

Summary

Centralizes all replaceAll("\\", "/") path normalization behind a suite of utility functions that return a branded ForwardSlashPath type, enabling static enforcement that backslash-to-forward-slash conversion has occurred before a path is used in contexts that require it (chokidar watchers, ES module specifiers, URL routing).

// Before — scattered inline normalization
this.basePath = basePath.replaceAll("\\", "/");
const fullPath = nodePath.join(destination, path).replaceAll("\\", "/");

// After — centralized, typed, enforced
this.basePath = toForwardSlashPath(basePath);
const fullPath = pathJoin(destination, path); // returns ForwardSlashPath

New utility (src/util/forward-slash-path.ts):

  • ForwardSlashPath — branded type (string & { readonly [__forwardSlashPath]: never }) using a unique symbol to prevent accidental assignment of un-normalized strings
  • toForwardSlashPath(path: string): ForwardSlashPath — the core normalization function
  • pathJoin(...paths: string[]): ForwardSlashPath — wraps nodePath.join, returning a forward-slash path
  • pathRelative(from: string, to: string): ForwardSlashPath — wraps nodePath.relative, returning a forward-slash path
  • pathDirname(path: string): ForwardSlashPath — wraps nodePath.dirname, returning a forward-slash path
  • pathResolve(...paths: string[]): ForwardSlashPath — wraps nodePath.resolve, returning a forward-slash path

Updated call sites — 13 files replaced inline .replaceAll("\\", "/") and toForwardSlashPath(nodePath.xxx(...)) patterns with the new utilities:

  • src/server/file-discovery.ts, module-loader.ts, transpiler.ts
  • src/typescript-generator/repository.ts, script.ts, generate.ts, operation-coder.ts, operation-type-coder.ts, parameters-type-coder.ts, prune.ts
  • src/migrate/update-route-types.ts, src/app.ts, bin/counterfact.js

Several files (transpiler.ts, script.ts, operation-coder.ts, operation-type-coder.ts, parameters-type-coder.ts, file-discovery.ts, app.ts) no longer import nodePath at all.

Test updates:

  • test/server/transpiler.test.ts — removed local forwardSlash helper; now imports toForwardSlashPath
  • test/util/forward-slash-path.test.ts — 14 unit tests covering all exported functions
Original Prompt

Create a utility function to replace replaceAll("\", "/") throughout the code.

Return a branded string and use that branded string wherever a path without backslashes is needed.

Manual acceptance tests

  • toForwardSlashPath("C:\\Users\\foo\\bar") returns "C:/Users/foo/bar" with no backslashes remaining
  • pathJoin("routes", "pets.ts") returns "routes/pets.ts" (forward slashes, cross-platform)
  • pathRelative("/a/b", "/a/b/c") returns "c" (forward slashes, cross-platform)
  • Server starts and handles requests normally — no regression in path-based routing
  • TypeScript compiler rejects assigning a plain string to a ForwardSlashPath-typed variable without going through one of the utility functions

Tasks

  • Created src/util/forward-slash-path.ts with ForwardSlashPath branded type, toForwardSlashPath, and four nodePath-wrapping helpers (pathJoin, pathRelative, pathDirname, pathResolve)
  • Replaced all inline .replaceAll("\\", "/") occurrences across 13 source files with toForwardSlashPath or the appropriate wrapper
  • Replaced all toForwardSlashPath(nodePath.xxx(...)) call-site patterns with the corresponding wrapper function
  • Updated test/server/transpiler.test.ts to import toForwardSlashPath instead of using a local helper
  • Added test/util/forward-slash-path.test.ts with 14 unit tests covering all exported functions
  • Added changeset (patch bump)

Copilot AI linked an issue Apr 14, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Add branded string utility for replacing backslashes in paths Add ForwardSlashPath branded type and toForwardSlashPath utility Apr 14, 2026
Copilot AI requested a review from pmcelhaney April 14, 2026 02:04
Copy link
Copy Markdown
Collaborator

@pmcelhaney pmcelhaney left a comment

Choose a reason for hiding this comment

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

The new function is mostly used to fix the output of nodePath.join() or nodePath.relative()

Create two new utility functions that wrap the nodePath functions so we can eliminate duplication.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 14, 2026

The new function is mostly used to fix the output of nodePath.join() or nodePath.relative()

Create two new utility functions that wrap the nodePath functions so we can eliminate duplication.

Done in commit 9faad6a. Added four wrapper functions to src/util/forward-slash-path.ts:

  • pathJoin(...paths) — wraps nodePath.join
  • pathRelative(from, to) — wraps nodePath.relative
  • pathDirname(path) — wraps nodePath.dirname
  • pathResolve(...paths) — wraps nodePath.resolve

All call sites updated; several files no longer import nodePath at all.

Copilot AI changed the title Add ForwardSlashPath branded type and toForwardSlashPath utility Add ForwardSlashPath branded type and forward-slash path utilities Apr 14, 2026
@pmcelhaney pmcelhaney marked this pull request as ready for review April 14, 2026 02:40
@pmcelhaney pmcelhaney enabled auto-merge April 14, 2026 02:40
Copilot AI requested a review from pmcelhaney April 14, 2026 02:40
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.

Branded string for forward slash paths

2 participants