提交 c6d52426 编写于 作者: J Joao Moreno

scm: resource tree model

上级 6d09fb3c
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
export const enum NodeType {
Branch,
Leaf
}
export interface LeafNode<T> {
readonly type: NodeType.Leaf;
readonly element: T;
}
export interface BranchNode<T> {
readonly type: NodeType.Branch;
readonly children: Map<string, Node<T>>;
}
export type Node<T> = BranchNode<T> | LeafNode<T>;
export class ResourceTree<T extends NonNullable<any>> {
readonly root: BranchNode<T> = { type: NodeType.Branch, children: new Map() };
constructor() { }
add(uri: URI, element: T): void {
const parts = uri.fsPath.split(/[\\\/]/).filter(p => !!p);
let node = this.root;
for (let i = 0; i < parts.length; i++) {
const name = parts[i];
let child = node.children.get(name);
if (!child) {
if (i < parts.length - 1) {
child = { type: NodeType.Branch, children: new Map() };
node.children.set(name, child);
} else {
child = { type: NodeType.Leaf, element };
node.children.set(name, child);
return;
}
}
if (child.type === NodeType.Leaf) {
if (i < parts.length - 1) {
throw new Error('Inconsistent tree: can\'t override leaf with branch.');
}
// replace
node.children.set(name, { type: NodeType.Leaf, element });
return;
} else if (i === parts.length - 1) {
throw new Error('Inconsistent tree: can\'t override branch with leaf.');
}
node = child;
}
}
delete(uri: URI): T | undefined {
const parts = uri.fsPath.split(/[\\\/]/).filter(p => !!p);
return this._delete(this.root, parts, 0);
}
private _delete(node: BranchNode<T>, parts: string[], index: number): T | undefined {
const name = parts[index];
const child = node.children.get(name);
if (!child) {
return undefined;
}
// not at end
if (index < parts.length - 1) {
if (child.type === NodeType.Leaf) {
throw new Error('Inconsistent tree: Expected a branch, found a leaf instead.');
} else {
const result = this._delete(child, parts, index + 1);
if (typeof result !== 'undefined' && child.children.size === 0) {
node.children.delete(name);
}
return result;
}
}
//at end
if (child.type === NodeType.Branch) {
// TODO: maybe we can allow this
throw new Error('Inconsistent tree: Expected a leaf, found a branch instead.');
}
node.children.delete(name);
return child.element;
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { ResourceTree, NodeType, BranchNode, LeafNode } from 'vs/base/common/resourceTree';
import { URI } from 'vs/base/common/uri';
suite('ResourceTree', function () {
test('ctor', function () {
const tree = new ResourceTree<string>();
assert.equal(tree.root.type, NodeType.Branch);
assert.equal(tree.root.children.size, 0);
});
test('simple', function () {
const tree = new ResourceTree<string>();
tree.add(URI.file('/foo/bar.txt'), 'bar contents');
assert.equal(tree.root.type, NodeType.Branch);
assert.equal(tree.root.children.size, 1);
let foo = tree.root.children.get('foo') as BranchNode<string>;
assert(foo);
assert.equal(foo.type, NodeType.Branch);
assert.equal(foo.children.size, 1);
let bar = foo.children.get('bar.txt') as LeafNode<string>;
assert(bar);
assert.equal(bar.type, NodeType.Leaf);
assert.equal(bar.element, 'bar contents');
tree.add(URI.file('/hello.txt'), 'hello contents');
assert.equal(tree.root.children.size, 2);
let hello = tree.root.children.get('hello.txt') as LeafNode<string>;
assert(hello);
assert.equal(hello.type, NodeType.Leaf);
assert.equal(hello.element, 'hello contents');
tree.delete(URI.file('/foo/bar.txt'));
assert.equal(tree.root.children.size, 1);
hello = tree.root.children.get('hello.txt') as LeafNode<string>;
assert(hello);
assert.equal(hello.type, NodeType.Leaf);
assert.equal(hello.element, 'hello contents');
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册