import { posix } from 'path';

/*
The ResolvePosixPath method resolves a sequence of paths or path segments into
an absolute path or path based on the `from` parameter.

The given sequence of paths is processed from right to left, with each
subsequent path prepended until an absolute path is constructed. For instance,
given the sequence of path segments: /foo, /bar, baz, calling
resolvePosixPath('/foo', '/bar', 'baz') would return /bar/baz because 'baz' is
not an absolute path but '/bar' + '/' + 'baz' is.

If, after processing all given path segments, an absolute path has not yet been
generated and the resolved path is not a subdirectory of `from`, the `from`
directory is used as the base path.

The resulting path is normalized and trailing slashes are removed unless the
path is resolved to the root directory.

Zero-length path segments are ignored.

If no path segments are passed, resolvePosixPath() will return the `from` path.
*/
export function ResolvePosixPath(from = '.') {
  return function resolvePosixPath(...paths: (string | undefined)[]) {
    let resolved: string | undefined = undefined;
    for (const path of paths.reverse()) {
      if (resolved && posix.isAbsolute(resolved)) {
        break;
      }
      if (path) {
        resolved = resolved ? posix.join(path, resolved) : path;
      }
    }
    if (resolved) {
      // Prepend 'from' path if 'resolved' is not absolute or a subdirectory of 'from'
      const relative = posix.relative(from, resolved);
      const isSubPath =
        relative && !relative.startsWith('..') && !posix.isAbsolute(relative);
      if (!posix.isAbsolute(resolved) && !isSubPath) {
        resolved = posix.join(from, resolved);
      }
    } else {
      resolved = from;
    }
    return posix.normalize(resolved);
  };
}
