Skip to content

Commit 9822576

Browse files
authored
fix(artifact-graph): normalize paths for cross-platform glob compatibility (#407)
Add FileSystemUtils.toPosixPath() utility and consolidate scattered path normalization patterns. This fixes Windows test failures where fast-glob couldn't match paths containing backslashes. Root cause: path.join() uses backslashes on Windows, but fast-glob requires forward slashes for glob patterns on all platforms. Changes: - Add toPosixPath() to FileSystemUtils for cross-platform path handling - Update artifact-graph/state.ts to normalize glob patterns - Consolidate path normalization in update.ts, validator.ts, and json-converter.ts to use the new utility
1 parent af273b8 commit 9822576

File tree

5 files changed

+19
-6
lines changed

5 files changed

+19
-6
lines changed

src/core/artifact-graph/state.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as path from 'node:path';
33
import fg from 'fast-glob';
44
import type { CompletedSet } from './types.js';
55
import type { ArtifactGraph } from './graph.js';
6+
import { FileSystemUtils } from '../../utils/file-system.js';
67

78
/**
89
* Detects which artifacts are completed by checking file existence in the change directory.
@@ -54,8 +55,10 @@ function isGlobPattern(pattern: string): boolean {
5455

5556
/**
5657
* Checks if a glob pattern has any matches.
58+
* Normalizes Windows backslashes to forward slashes for cross-platform glob compatibility.
5759
*/
5860
function hasGlobMatches(pattern: string): boolean {
59-
const matches = fg.sync(pattern, { onlyFiles: true });
61+
const normalizedPattern = FileSystemUtils.toPosixPath(pattern);
62+
const matches = fg.sync(normalizedPattern, { onlyFiles: true });
6063
return matches.length > 0;
6164
}

src/core/converters/json-converter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import path from 'path';
33
import { MarkdownParser } from '../parsers/markdown-parser.js';
44
import { ChangeParser } from '../parsers/change-parser.js';
55
import { Spec, Change } from '../schemas/index.js';
6+
import { FileSystemUtils } from '../../utils/file-system.js';
67

78
export class JsonConverter {
89
convertSpecToJson(filePath: string): string {
@@ -43,7 +44,7 @@ export class JsonConverter {
4344
}
4445

4546
private extractNameFromPath(filePath: string): string {
46-
const normalizedPath = filePath.replaceAll('\\', '/');
47+
const normalizedPath = FileSystemUtils.toPosixPath(filePath);
4748
const parts = normalizedPath.split('/');
4849

4950
for (let i = parts.length - 1; i >= 0; i--) {

src/core/update.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export class UpdateCommand {
107107

108108
if (updatedSlashFiles.length > 0) {
109109
// Normalize to forward slashes for cross-platform log consistency
110-
const normalized = updatedSlashFiles.map((p) => p.replace(/\\/g, '/'));
110+
const normalized = updatedSlashFiles.map((p) => FileSystemUtils.toPosixPath(p));
111111
summaryParts.push(`Updated slash commands: ${normalized.join(', ')}`);
112112
}
113113

src/core/validation/validator.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import { SpecSchema, ChangeSchema, Spec, Change } from '../schemas/index.js';
55
import { MarkdownParser } from '../parsers/markdown-parser.js';
66
import { ChangeParser } from '../parsers/change-parser.js';
77
import { ValidationReport, ValidationIssue, ValidationLevel } from './types.js';
8-
import {
8+
import {
99
MIN_PURPOSE_LENGTH,
1010
MAX_REQUIREMENT_TEXT_LENGTH,
11-
VALIDATION_MESSAGES
11+
VALIDATION_MESSAGES
1212
} from './constants.js';
1313
import { parseDeltaSpec, normalizeRequirementName } from '../parsers/requirement-blocks.js';
14+
import { FileSystemUtils } from '../../utils/file-system.js';
1415

1516
export class Validator {
1617
private strictMode: boolean;
@@ -359,7 +360,7 @@ export class Validator {
359360
}
360361

361362
private extractNameFromPath(filePath: string): string {
362-
const normalizedPath = filePath.replaceAll('\\', '/');
363+
const normalizedPath = FileSystemUtils.toPosixPath(filePath);
363364
const parts = normalizedPath.split('/');
364365

365366
// Look for the directory name after 'specs' or 'changes'

src/utils/file-system.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ function findMarkerIndex(
4242
}
4343

4444
export class FileSystemUtils {
45+
/**
46+
* Converts a path to use forward slashes (POSIX style).
47+
* Essential for cross-platform compatibility with glob libraries like fast-glob.
48+
*/
49+
static toPosixPath(p: string): string {
50+
return p.replace(/\\/g, '/');
51+
}
52+
4553
private static isWindowsBasePath(basePath: string): boolean {
4654
return /^[A-Za-z]:[\\/]/.test(basePath) || basePath.startsWith('\\');
4755
}

0 commit comments

Comments
 (0)