Skip to content

Commit

Permalink
Improve Windows drive letter URI handling (#1816)
Browse files Browse the repository at this point in the history
  • Loading branch information
sailingKieler authored Feb 26, 2025
1 parent fa8371b commit 0e058c7
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 3 deletions.
23 changes: 20 additions & 3 deletions packages/langium/src/utils/uri-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,32 @@ export namespace UriUtils {
export const joinPath = Utils.joinPath;
export const resolvePath = Utils.resolvePath;

const isWindows = typeof process === 'object' && process?.platform === 'win32';

export function equals(a?: URI | string, b?: URI | string): boolean {
return a?.toString() === b?.toString();
}

export function relative(from: URI | string, to: URI | string): string {
const fromPath = typeof from === 'string' ? from : from.path;
const toPath = typeof to === 'string' ? to : to.path;
const fromPath = typeof from === 'string' ? URI.parse(from).path : from.path;
const toPath = typeof to === 'string' ? URI.parse(to).path : to.path;
const fromParts = fromPath.split('/').filter(e => e.length > 0);
const toParts = toPath.split('/').filter(e => e.length > 0);
const toParts = toPath.split('/').filter(e => e.length > 0);

if (isWindows) {
const upperCaseDriveLetter = /^[A-Z]:$/;
if (fromParts[0] && upperCaseDriveLetter.test(fromParts[0])) {
fromParts[0] = fromParts[0].toLowerCase();
}
if (toParts[0] && upperCaseDriveLetter.test(toParts[0])) {
toParts[0] = toParts[0].toLowerCase();
}
if (fromParts[0] !== toParts[0]) {
// in case of different drive letters, we cannot compute a relative path, so...
return toPath.substring(1); // fall back to full 'to' path, drop the leading '/', keep everything else as is for good comparability
}
}

let i = 0;
for (; i < fromParts.length; i++) {
if (fromParts[i] !== toParts[i]) {
Expand Down
24 changes: 24 additions & 0 deletions packages/langium/test/utils/uri-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ describe('URI Utils', () => {
expect(UriUtils.relative(from, to)).toBe('../d.txt');
});

test.skipIf(process.platform !== 'win32')('relative path in parent directory win32, uppercase drive letters', () => {
const from = URI.file('C:\\a\\b');
const to = URI.file('C:\\a\\d.txt');
expect(UriUtils.relative(from, to)).toBe('../d.txt');
});

test.skipIf(process.platform !== 'win32')('relative path in parent directory win32, mixed drive letter cases 1', () => {
const from = URI.file('C:\\a\\b');
const to = URI.file('c:\\a\\d.txt');
expect(UriUtils.relative(from, to)).toBe('../d.txt');
});

test.skipIf(process.platform !== 'win32')('relative path in parent directory win32, mixed drive letter cases 2', () => {
const from = URI.file('c:\\a\\b');
const to = URI.file('C:\\a\\d.txt');
expect(UriUtils.relative(from, to)).toBe('../d.txt');
});

test('relative path in sub directory', () => {
const from = URI.file('/a');
const to = URI.file('/a/b/c.txt');
Expand All @@ -51,6 +69,12 @@ describe('URI Utils', () => {
expect(UriUtils.relative(from, to)).toBe('../c/d.txt');
});

test.skipIf(process.platform !== 'win32')('different win32 drive letters', () => {
const from = URI.file('c:\\a\\b');
const to = URI.file('D:\\a\\c\\d.txt');
expect(UriUtils.relative(from, to)).toBe('D:/a/c/d.txt');
});

test('Equal uris are equal', () => {
const uri1 = 'file:///a/b';
const uri2 = 'file:///a/b';
Expand Down

0 comments on commit 0e058c7

Please # to comment.