-
-
Save creationix/7435851 to your computer and use it in GitHub Desktop.
// Joins path segments. Preserves initial "/" and resolves ".." and "." | |
// Does not support using ".." to go above/outside the root. | |
// This means that join("foo", "../../bar") will not resolve to "../bar" | |
function join(/* path segments */) { | |
// Split the inputs into a list of path commands. | |
var parts = []; | |
for (var i = 0, l = arguments.length; i < l; i++) { | |
parts = parts.concat(arguments[i].split("/")); | |
} | |
// Interpret the path commands to get the new resolved path. | |
var newParts = []; | |
for (i = 0, l = parts.length; i < l; i++) { | |
var part = parts[i]; | |
// Remove leading and trailing slashes | |
// Also remove "." segments | |
if (!part || part === ".") continue; | |
// Interpret ".." to pop the last segment | |
if (part === "..") newParts.pop(); | |
// Push new path segments. | |
else newParts.push(part); | |
} | |
// Preserve the initial slash if there was one. | |
if (parts[0] === "") newParts.unshift(""); | |
// Turn back into a single string path. | |
return newParts.join("/") || (newParts.length ? "/" : "."); | |
} | |
// A simple function to get the dirname of a path | |
// Trailing slashes are ignored. Leading slash is preserved. | |
function dirname(path) { | |
return join(path, ".."); | |
} |
sorry to ask, but what about the OS with the 'other' slashes? ;)
@japj +1 ;-) Otherwise it's strictly network (not FS) dedicated version.
Is there a license you could mention with this? Public domain doesn't exist everywhere as a concept and unattributed works can't be utilized without serious stares from legal and threats of the attack sharks. MIT, and I'd love you forever?
Some issues I experienced when trying out this approach :
- Trailing
/
isn't preserved - Double
//
are replaced with/
when the first path is an absolute path that starts with the protocol (eg.blob://
,file://
,http://
,https://
, ...) - If your first path starts with
../
, it is stripped away
For me, that makes this approach pretty much unusable.
MSDOS cmd.exe and powershell accept '/' as well as '\'. It's only obscenely obsolete systems that reject '/' as a file separator. You might have a real reason for using a 386 system running MSDOS 3.1, but it probably doesn't involve running javascript :-)
Do you have a license, or at least allow other people to use this? It's beautiful, great and simple. Maybe you also want to check for escaped slashes (\/
on Unix), although URL encoding usually takes care of that well. :)
My variant:
/**
* A simple analog of Node.js's `path.join(...)`.
* https://gist.github.com/creationix/7435851#gistcomment-3698888
* @param {...string} segments
* @return {string}
*/
export default function joinPath(...segments) {
const parts = segments.reduce((parts, segment) => {
// Remove leading slashes from non-first part.
if (parts.length > 0) {
segment = segment.replace(/^\//, '')
}
// Remove trailing slashes.
segment = segment.replace(/\/$/, '')
return parts.concat(segment.split('/'))
}, [])
const resultParts = []
for (const part of parts) {
if (part === '.') {
continue
}
if (part === '..') {
resultParts.pop()
continue
}
resultParts.push(part)
}
return resultParts.join('/')
}
This had some interesting design constraints that allowed it to be very simple.
join("foo", "../../bar")
that would resolve to"../bar"
join("some/path", "/looks/absolute")
will resolve to"some/path/looks/absolute"
and not"/looks/absolute"
.