0

I'm trying to figure out a way to compare two absolute(ish!) file locations and return the relative path from one to another in the shortest way possible.

/*
Example 1:
..\root\folder\subFolder\myCurrent.file
..\root\folder\subFolder\img\myTarget.image

Expected result:
.\img\myTarget.image

Example 2:
..\root\folder\subFolder\myCurrent.file
..\root\folder\otherSubFolder\img\myTarget.image

Expected result:
..\otherSubFolder\img\myTarget.image

Example 3:
..\root\folder\subFolder\myCurrent.file
..\root\folder\subFolder\myTarget.image

Expected result:
myTarget.image
*/

I tried to split the paths to arrays and compare length and values, but it turned out to be a complete mess and I didn't even manage to do it yet...

const currentFilePath = activepath.split('\\')
const currentDir = currentFilePath[currentFilePath.indexOf(currentFilePath[currentFilePath.length - 2])];
const targetFilePath = file.path.split('\\');
const targetDir = targetFilePath[targetFilePath.indexOf(targetFilePath[targetFilePath.length - 2])];
const currentFileDepth = currentFilePath.length;
// and so on...

I would like a decent, clean way to figure this out...

2 Answers 2

2

You could split both paths, then get the unique components from both arrays using .filter(). Then grab the unique components pertaining to the parts of the second path by using .filter() again and finally using .join('\\') to create your result:

const comparePaths = (a, b) => {
  const a_parts = a.split('\\');
  const b_parts = b.split('\\');
  const arr = [...a_parts, ...b_parts];
  const diffs = arr.filter(item => arr.indexOf(item) === arr.lastIndexOf(item));
  let path_parts = diffs.filter(part => b_parts.includes(part));
  const res = ".".repeat(path_parts.length && path_parts.length-1 || 0) +'\\'+ path_parts.join('\\');
  return res;
}

console.log(comparePaths("..\\root\\folder\\subFolder\\myCurrent.file",
"..\\root\\folder\\subFolder\\img\\myTarget.image"));

console.log(comparePaths("..\\root\\folder\\subFolder\\myCurrent.file",
"..\\root\\folder\\otherSubFolder\\img\\myTarget.image"));

console.log(comparePaths("..\\foo\\bar\\foobar.js",
"..\\foo\\bar\\foobar.js"));

Sign up to request clarification or add additional context in comments.

3 Comments

Sorry, but the first and third logs are wrong regarding what I'm trying to achieve. They should respectively start by '.\' and '' instead of '..\' for both. Those two paths would not resolve properly.
So your expected output for both should start with .\? Because that isn't what's written in the question
The expected output should be a valid file system path linking the current file to the target file. I provided another example so you can spot the difference.
1

For node.js, there's a built-in for this:

let path = require('path').win32;

r = path.relative(
    "..\\root\\folder\\subFolder\\myCurrent.file",
    "..\\root\\folder\\subFolder\\img\\myTarget.image");

console.log(r) // ..\img\myTarget.image

For browsers, google around for a port, or just grab the source, which is small and transparent.

path.relative expects the first argument to be a directory, if it's a file name, you have to obtain the directory first:

let path = require('path').win32;

r = path.relative(
    path.dirname("..\\root\\folder\\subFolder\\myCurrent.file"),
    "..\\root\\folder\\subFolder\\img\\myTarget.image");

console.log(r) // img\myTarget.image

2 Comments

Just tried that, and it deserved the upvote I gave you. However, as depicted in your snippet, the function returns with a string starting in "..\", but imagine if this is the path to an image that I would insert as <img>'s src... it would broke. Why is it different than the expected ".\" ?
Why is the doc so few detailed about this ? Thanks anyway !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.