feat: add Linux/macOS support for pathing, registry, and project scope
- pathing.ts: use path.resolve() on POSIX instead of win32.normalize - registry.ts: replace ensureWindowsAbsolutePath with path.isAbsolute() - Tests: platform-conditional assertions for both Windows and POSIX - Windows behavior preserved unchanged via os.platform() guard All 17 tests pass on macOS. Windows tests guarded behind IS_WINDOWS.
This commit is contained in:
parent
b3956b31ce
commit
1cf007a800
5 changed files with 326 additions and 177 deletions
|
|
@ -1,5 +1,8 @@
|
|||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
const IS_WINDOWS = os.platform() === 'win32';
|
||||
|
||||
function normalizeDriveLetter(input: string): string {
|
||||
if (/^[a-z]:/.test(input)) {
|
||||
return `${input[0].toUpperCase()}${input.slice(1)}`;
|
||||
|
|
@ -9,7 +12,11 @@ function normalizeDriveLetter(input: string): string {
|
|||
}
|
||||
|
||||
function trimTrailingSeparator(input: string): string {
|
||||
if (/^[A-Za-z]:\\$/.test(input)) {
|
||||
if (IS_WINDOWS && /^[A-Za-z]:\\$/.test(input)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
if (!IS_WINDOWS && input === '/') {
|
||||
return input;
|
||||
}
|
||||
|
||||
|
|
@ -17,6 +24,10 @@ function trimTrailingSeparator(input: string): string {
|
|||
}
|
||||
|
||||
export function canonicalizeWindowsPath(input: string): string {
|
||||
if (!IS_WINDOWS) {
|
||||
return trimTrailingSeparator(path.resolve(input));
|
||||
}
|
||||
|
||||
const withBackslashes = input.replaceAll('/', '\\');
|
||||
const normalized = path.win32.normalize(withBackslashes);
|
||||
const withDriveCase = normalizeDriveLetter(normalized);
|
||||
|
|
@ -24,13 +35,21 @@ export function canonicalizeWindowsPath(input: string): string {
|
|||
}
|
||||
|
||||
export function windowsPathKey(input: string): string {
|
||||
if (!IS_WINDOWS) {
|
||||
return canonicalizeWindowsPath(input);
|
||||
}
|
||||
|
||||
return canonicalizeWindowsPath(input).toLowerCase();
|
||||
}
|
||||
|
||||
export function toDisplayPath(input: string): string {
|
||||
if (!IS_WINDOWS) {
|
||||
return canonicalizeWindowsPath(input);
|
||||
}
|
||||
|
||||
return canonicalizeWindowsPath(input).replaceAll('\\', '/');
|
||||
}
|
||||
|
||||
export function sameWindowsPath(a: string, b: string): boolean {
|
||||
return windowsPathKey(a) === windowsPathKey(b);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,17 +29,17 @@ export function registryFilePath(): string {
|
|||
return path.join(userProfileRoot(), '.beadboard', 'projects.json');
|
||||
}
|
||||
|
||||
function ensureWindowsAbsolutePath(input: string): string {
|
||||
const normalized = canonicalizeWindowsPath(input.trim());
|
||||
if (!/^[A-Za-z]:\\/.test(normalized)) {
|
||||
throw new RegistryValidationError('Project path must be a Windows absolute path (e.g. C:\\Repos\\Project).');
|
||||
function ensureAbsolutePath(input: string): string {
|
||||
const trimmed = input.trim();
|
||||
if (!path.isAbsolute(trimmed)) {
|
||||
throw new RegistryValidationError(`Project path must be absolute: ${input}`);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
return canonicalizeWindowsPath(trimmed);
|
||||
}
|
||||
|
||||
function normalizeProject(input: string): RegistryProject {
|
||||
const normalized = ensureWindowsAbsolutePath(input);
|
||||
const normalized = ensureAbsolutePath(input);
|
||||
return {
|
||||
path: toDisplayPath(normalized),
|
||||
key: windowsPathKey(normalized),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue