提交 fbbc8c59 编写于 作者: M Martin Aeschlimann

make path.dirname root aware (for #64429)

上级 ff9f7cfb
......@@ -17,6 +17,11 @@ export const sep = '/';
*/
export const nativeSep = isWindows ? '\\' : '/';
function isPathSeparator(code: number) {
return code === CharCode.Slash || code === CharCode.Backslash;
}
/**
* @param path the path to get the dirname from
* @param separator the separator to use
......@@ -24,20 +29,32 @@ export const nativeSep = isWindows ? '\\' : '/';
*
*/
export function dirname(path: string, separator = nativeSep): string {
const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
if (idx === 0) {
const len = path.length;
if (len === 0) {
return '.';
} else if (~idx === 0) {
return path[0];
} else if (~idx === path.length - 1) {
return dirname(path.substring(0, path.length - 1));
} else {
let res = path.substring(0, ~idx);
if (isWindows && res[res.length - 1] === ':') {
res += separator; // make sure drive letters end with backslash
} else if (len === 1) {
return isPathSeparator(path.charCodeAt(0)) ? path : '.';
}
const root = getRoot(path, separator);
let rootLength = root.length;
if (rootLength >= len) {
return root; // matched the root
}
if (rootLength === 0 && isPathSeparator(path.charCodeAt(0))) {
rootLength = 1; // absolute paths stay absolute paths.
}
let i = len - 1;
if (i > rootLength) {
i--; // no need to look at the last character. If it's a trailing slash, we ignore it.
while (i > rootLength && !isPathSeparator(path.charCodeAt(i))) {
i--;
}
}
return res;
if (i === 0) {
return '.'; // it was a relative path with a single segment, no root. Nodejs returns '.' here.
}
return path.substr(0, i);
}
/**
......
......@@ -76,6 +76,9 @@ export function dirname(resource: URI): URI | null {
if (resource.scheme === Schemas.file) {
return URI.file(paths.dirname(fsPath(resource)));
}
if (resource.path.length === 0) {
return resource;
}
let dirname = paths.dirname(resource.path, '/');
if (resource.authority && dirname.length && dirname.charCodeAt(0) !== CharCode.Slash) {
return null; // If a URI contains an authority component, then the path component must either be empty or begin with a CharCode.Slash ("/") character
......
......@@ -8,21 +8,34 @@ import * as platform from 'vs/base/common/platform';
suite('Paths', () => {
test('dirname', () => {
assert.equal(paths.dirname('foo/bar'), 'foo');
assert.equal(paths.dirname('foo\\bar'), 'foo');
assert.equal(paths.dirname('/foo/bar'), '/foo');
assert.equal(paths.dirname('\\foo\\bar'), '\\foo');
assert.equal(paths.dirname('/foo'), '/');
assert.equal(paths.dirname('\\foo'), '\\');
assert.equal(paths.dirname('/'), '/');
assert.equal(paths.dirname('\\'), '\\');
assert.equal(paths.dirname('foo'), '.');
assert.equal(paths.dirname('/folder/'), '/');
if (platform.isWindows) {
assert.equal(paths.dirname('c:\\some\\file.txt'), 'c:\\some');
assert.equal(paths.dirname('c:\\some'), 'c:\\');
function assertDirname(path: string, expected: string, win = false) {
const actual = paths.dirname(path, win ? '\\' : '/');
if (actual !== expected) {
assert.fail(`${path}: expected: ${expected}, ours: ${actual}`);
}
}
test('dirname', () => {
assertDirname('foo/bar', 'foo');
assertDirname('foo\\bar', 'foo', true);
assertDirname('/foo/bar', '/foo');
assertDirname('\\foo\\bar', '\\foo', true);
assertDirname('/foo', '/');
assertDirname('\\foo', '\\', true);
assertDirname('/', '/');
assertDirname('\\', '\\', true);
assertDirname('foo', '.');
assertDirname('f', '.');
assertDirname('f/', '.');
assertDirname('/folder/', '/');
assertDirname('c:\\some\\file.txt', 'c:\\some', true);
assertDirname('c:\\some', 'c:\\', true);
assertDirname('c:\\', 'c:\\', true);
assertDirname('c:', 'c:', true);
assertDirname('\\\\server\\share\\some\\path', '\\\\server\\share\\some', true);
assertDirname('\\\\server\\share\\some', '\\\\server\\share\\', true);
assertDirname('\\\\server\\share\\', '\\\\server\\share\\', true);
});
test('normalize', () => {
......
......@@ -47,6 +47,7 @@ suite('Resources', () => {
assert.equal(dirname(URI.file('c:\\some\\file\\'))!.toString(), 'file:///c%3A/some');
assert.equal(dirname(URI.file('c:\\some'))!.toString(), 'file:///c%3A/');
assert.equal(dirname(URI.file('C:\\some'))!.toString(), 'file:///c%3A/');
assert.equal(dirname(URI.file('c:\\'))!.toString(), 'file:///c%3A/');
} else {
assert.equal(dirname(URI.file('/some/file/test.txt'))!.toString(), 'file:///some/file');
assert.equal(dirname(URI.file('/some/file/'))!.toString(), 'file:///some');
......@@ -56,6 +57,8 @@ suite('Resources', () => {
assert.equal(dirname(URI.parse('foo://a/some/file/'))!.toString(), 'foo://a/some');
assert.equal(dirname(URI.parse('foo://a/some/file'))!.toString(), 'foo://a/some');
assert.equal(dirname(URI.parse('foo://a/some'))!.toString(), 'foo://a/');
assert.equal(dirname(URI.parse('foo://a/'))!.toString(), 'foo://a/');
assert.equal(dirname(URI.parse('foo://a'))!.toString(), 'foo://a');
// does not explode (https://github.com/Microsoft/vscode/issues/41987)
dirname(URI.from({ scheme: 'file', authority: '/users/someone/portal.h' }));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册