From 570eb9dcea4b629ecc7e399393528556d89be8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= Date: Thu, 18 Jul 2024 15:58:50 +0300 Subject: [PATCH] path: fix relative on Windows --- benchmark/path/relative-win32.js | 1 + lib/path.js | 40 +++++++++++++++++++++++++++++ test/parallel/test-path-relative.js | 5 ++++ 3 files changed, 46 insertions(+) diff --git a/benchmark/path/relative-win32.js b/benchmark/path/relative-win32.js index e513b828533ddb..219c6a31e6aed7 100644 --- a/benchmark/path/relative-win32.js +++ b/benchmark/path/relative-win32.js @@ -9,6 +9,7 @@ const bench = common.createBenchmark(main, { ['C:\\foo\\bar\\baz', 'C:\\foo\\bar\\baz'].join('|'), ['C:\\foo\\BAR\\BAZ', 'C:\\foo\\bar\\baz'].join('|'), ['C:\\foo\\bar\\baz\\quux', 'C:\\'].join('|'), + ['c:\\İ\\a\\İ', 'c:\\İ\\b\\İ\\test.txt', '..\\..\\b\\İ\\test.txt'].join('|'), ], n: [1e5], }); diff --git a/lib/path.js b/lib/path.js index e9dec3f7d361d3..c6d1095148aab9 100644 --- a/lib/path.js +++ b/lib/path.js @@ -22,12 +22,16 @@ 'use strict'; const { + ArrayPrototypeJoin, + ArrayPrototypeSlice, FunctionPrototypeBind, StringPrototypeCharCodeAt, StringPrototypeIndexOf, StringPrototypeLastIndexOf, + StringPrototypeRepeat, StringPrototypeReplace, StringPrototypeSlice, + StringPrototypeSplit, StringPrototypeToLowerCase, } = primordials; @@ -540,6 +544,42 @@ const win32 = { if (from === to) return ''; + if (fromOrig.length !== from.length || toOrig.length !== to.length) { + const fromSplit = StringPrototypeSplit(fromOrig, '\\'); + const toSplit = StringPrototypeSplit(toOrig, '\\'); + if (fromSplit[fromSplit.length - 1] === '') { + fromSplit.pop(); + } + if (toSplit[toSplit.length - 1] === '') { + toSplit.pop(); + } + + const fromLen = fromSplit.length; + const toLen = toSplit.length; + const length = fromLen < toLen ? fromLen : toLen; + + let i; + for (i = 0; i < length; i++) { + if (StringPrototypeToLowerCase(fromSplit[i]) !== StringPrototypeToLowerCase(toSplit[i])) { + break; + } + } + + if (i === 0) { + return toOrig; + } else if (i === length) { + if (toLen > length) { + return ArrayPrototypeJoin(ArrayPrototypeSlice(toSplit, i), '\\'); + } + if (fromLen > length) { + return StringPrototypeRepeat('..\\', fromLen - 1 - i) + '..'; + } + return ''; + } + + return StringPrototypeRepeat('..\\', fromLen - i) + ArrayPrototypeJoin(ArrayPrototypeSlice(toSplit, i), '\\'); + } + // Trim any leading backslashes let fromStart = 0; while (fromStart < from.length && diff --git a/test/parallel/test-path-relative.js b/test/parallel/test-path-relative.js index f6a9f5662a6c24..999ef93784b523 100644 --- a/test/parallel/test-path-relative.js +++ b/test/parallel/test-path-relative.js @@ -32,6 +32,11 @@ const relativeTests = [ ['\\\\foo\\baz', '\\\\foo\\baz-quux', '..\\baz-quux'], ['C:\\baz', '\\\\foo\\bar\\baz', '\\\\foo\\bar\\baz'], ['\\\\foo\\bar\\baz', 'C:\\baz', 'C:\\baz'], + ['c:\\a\\İ', 'c:\\a\\İ\\test.txt', 'test.txt'], + ['c:\\İ\\a\\İ', 'c:\\İ\\b\\İ\\test.txt', '..\\..\\b\\İ\\test.txt'], + ['c:\\İ\\a\\i̇', 'c:\\İ\\b\\İ\\test.txt', '..\\..\\b\\İ\\test.txt'], + ['c:\\i̇\\a\\İ', 'c:\\İ\\b\\İ\\test.txt', '..\\..\\b\\İ\\test.txt'], + ['c:\\ß\\a\\ß', 'c:\\ß\\b\\ß\\test.txt', '..\\..\\b\\ß\\test.txt'], ], ], [ path.posix.relative,