All files / views/trees/definition-tree/nodes/collections collection-class-node.ts

100% Statements 35/35
100% Branches 10/10
100% Functions 7/7
100% Lines 35/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96                      11x   11x       12x       3x 3x   3x 2x 1x       2x       26x 26x 26x 26x 26x   26x     46x 4x     42x 17x   17x 17x   25x   25x 25x       26x   4x       22x               29x   29x   29x 34x   34x     29x       1x       1x      
import * as vscode from "vscode";
import { TreeNode, sortByLabel } from "@src/views/trees/tree-node";
import { ConceptClassNode } from "../concepts/concept-class-node";
import { ClassNodeBase } from "../classes/class-node-base";
import { DefinitionTreeNode } from "../../definition-tree-node";
 
/**
 * Node of a SKOS collection in the definition tree.
 */
export class CollectionClassNode extends ClassNodeBase {
	override getIcon(): vscode.ThemeIcon | undefined {
		const isOrdered = this.vocabulary.isOrderedCollection(this.getDocumentGraphs(), this.uri);
 
		return new vscode.ThemeIcon(isOrdered ? 'rdf-collection-ordered' : 'rdf-collection', this.getIconColor());
	}
 
	override getIconColor() {
		return new vscode.ThemeColor("mentor.color.concept");
	}
 
	override hasChildren(): boolean {
		const graphs = this.getDocumentGraphs();
		const path = this.getPathUris();
 
		for (const m of this.vocabulary.getCollectionMembers(graphs, this.uri)) {
			if (!path.has(m)) {
				return true;
			}
		}
 
		return false;
	}
 
	override getChildren(): TreeNode[] {
		const graphs = this.getDocumentGraphs();
		const path = this.getPathUris();
		const collectionNodes: TreeNode[] = [];
		const conceptNodes: TreeNode[] = [];
		const members: TreeNode[] = [];
 
		for (const m of this.vocabulary.getCollectionMembers(graphs, this.uri)) {
			// Note: Members that are already on the path to this node are skipped so that cyclic
			// collection definitions cannot be expanded indefinitely.
			if (path.has(m)) {
				continue;
			}
 
			if (this.vocabulary.isCollection(graphs, m)) {
				const node = this.createChildNode(CollectionClassNode, m);
 
				collectionNodes.push(node);
				members.push(node);
			} else {
				const node = this.createChildNode(ConceptClassNode, m);
 
				conceptNodes.push(node);
				members.push(node);
			}
		}
 
		if (this.vocabulary.isOrderedCollection(graphs, this.uri)) {
			// Preserve the order of the member list for ordered collections.
			return members;
		}
 
		// Nested collections are listed before the concepts of the collection.
		return [...sortByLabel(collectionNodes), ...sortByLabel(conceptNodes)];
	}
 
	/**
	 * Get the IRIs of this node and of all its ancestor nodes in the tree.
	 * @returns A set of resource IRIs.
	 */
	protected getPathUris(): Set<string> {
		const result = new Set<string>([this.uri]);
 
		let parent: DefinitionTreeNode | undefined = this.parent;
 
		while (parent) {
			result.add(parent.uri);
 
			parent = parent.parent;
		}
 
		return result;
	}
 
	override getClassNode(iri: string) {
		return this.createChildNode(CollectionClassNode, iri);
	}
 
	override getIndividualNode(iri: string) {
		return this.createChildNode(ConceptClassNode, iri);
	}
}