Skip to content

Commit f7debef

Browse files
scm1400mathio
andauthored
fix(cli): normalize paths and improve compatibility on windows (#946)
* fix(cli): normalize paths and improve compatibility on windows Add helper function for path normalization on Windows platform Use normalized paths when validating path patterns Convert glob patterns to Unix-style for Windows compatibility Normalize returned paths to ensure cross-platform compatibility * fix(cli): add changeset * fix(cli): clean up path normalization logic, run prettier --------- Co-authored-by: Matej Lednicky <[email protected]>
1 parent 24bc930 commit f7debef

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

.changeset/breezy-pumas-fix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"lingo.dev": patch
3+
---
4+
5+
normalize paths and improve compatibility on windows

packages/cli/src/cli/utils/buckets.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,21 +87,29 @@ function extractPathPatterns(
8787
return result;
8888
}
8989

90+
// Windows path normalization helper function
91+
function normalizePath(filepath: string): string {
92+
const normalized = path.normalize(filepath);
93+
// Ensure case consistency on Windows
94+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
95+
}
96+
9097
// Path expansion
9198
function expandPlaceholderedGlob(
9299
_pathPattern: string,
93100
sourceLocale: string,
94101
): string[] {
95-
// Throw if pathPattern is an absolute path
96102
const absolutePathPattern = path.resolve(_pathPattern);
97-
const pathPattern = path.relative(process.cwd(), absolutePathPattern);
98-
// Throw if pathPattern points outside the current working directory
99-
if (path.relative(process.cwd(), pathPattern).startsWith("..")) {
103+
const pathPattern = normalizePath(
104+
path.relative(process.cwd(), absolutePathPattern),
105+
);
106+
if (pathPattern.startsWith("..")) {
100107
throw new CLIError({
101108
message: `Invalid path pattern: ${pathPattern}. Path pattern must be within the current working directory.`,
102109
docUrl: "invalidPathPattern",
103110
});
104111
}
112+
105113
// Throw error if pathPattern contains "**" – we don't support recursive path patterns
106114
if (pathPattern.includes("**")) {
107115
throw new CLIError({
@@ -124,15 +132,27 @@ function expandPlaceholderedGlob(
124132
);
125133
// substitute [locale] in pathPattern with sourceLocale
126134
const sourcePathPattern = pathPattern.replaceAll(/\[locale\]/g, sourceLocale);
135+
// Convert to Unix-style for Windows compatibility
136+
const unixStylePattern = sourcePathPattern.replace(/\\/g, "/");
137+
127138
// get all files that match the sourcePathPattern
128139
const sourcePaths = glob
129-
.sync(sourcePathPattern, { follow: true, withFileTypes: true })
140+
.sync(unixStylePattern, {
141+
follow: true,
142+
withFileTypes: true,
143+
windowsPathsNoEscape: true, // Windows path support
144+
})
130145
.filter((file) => file.isFile() || file.isSymbolicLink())
131146
.map((file) => file.fullpath())
132-
.map((fullpath) => path.relative(process.cwd(), fullpath));
147+
.map((fullpath) => normalizePath(path.relative(process.cwd(), fullpath)));
148+
133149
// transform each source file path back to [locale] placeholder paths
134150
const placeholderedPaths = sourcePaths.map((sourcePath) => {
135-
const sourcePathChunks = sourcePath.split(path.sep);
151+
// Normalize path returned by glob for platform compatibility
152+
const normalizedSourcePath = normalizePath(
153+
sourcePath.replace(/\//g, path.sep),
154+
);
155+
const sourcePathChunks = normalizedSourcePath.split(path.sep);
136156
localeSegmentIndexes.forEach((localeSegmentIndex) => {
137157
// Find the position of the "[locale]" placeholder within the segment
138158
const pathPatternChunk = pathPatternChunks[localeSegmentIndex];

0 commit comments

Comments
 (0)