All files / views/trees/definition-tree/nodes/classes class-node-base.ts

100% Statements 36/36
100% Branches 8/8
100% Functions 11/11
100% Lines 36/36

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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155                          380x             54x                       78x                 8x   8x         5x 2x       8x                 6x       1x 1x   1x       8x       53x 20x     33x 25x 1x       32x       37x 37x   37x 25x     37x   37x 29x   29x 13x     29x     37x                                             6x 6x     6x                 55x 55x         55x    
import * as vscode from "vscode";
import { container } from 'tsyringe';
import { VocabularyRepository } from "@faubulous/mentor-rdf";
import { ServiceToken } from '@src/services/tokens';
import { sortByLabel } from "@src/views/trees/tree-node";
import { DefinitionTreeNode } from "../../definition-tree-node";
 
/**
 * Base class for all nodes that represent classes in the definition tree, such as classes and properties.
 * It is also used as a base for parent nodes of individual lists such as named individuals, shapes, collections, etc.
 */
export abstract class ClassNodeBase extends DefinitionTreeNode {
	protected get vocabulary() {
		return container.resolve<VocabularyRepository>(ServiceToken.VocabularyRepository);
	}
 
	/**
	 * Indicates whether class instances should be returned by the {@link getChildren} method.
	 */
	showIndividuals(): boolean {
		return true;
	}
 
	/**
	 * Get the graph IRIs of the document context and possibly extended ontology graphs. This method should be 
	 * used when querying type or sub-class relationships and may be overloaded to provide additional relevant
	 * graphs such as the SHACL spec.
	 * 
	 * Note: Used in {@link getSubClassIris}.
	 * @returns An array of graph IRIs.
	 */
	getOntologyGraphs(): string[] {
		return this.document.graphs;
	}
 
	/**
	 * Get the icon name of a class depending on its properties in the document graph.
	 * @param classIri IRI of a class.
	 * @returns The icon name of the class.
	 */
	getIconNameFromClass(classIri?: string): string {
		let iconName = 'rdf-class';
 
		if (classIri) {
			// if (!mentor.vocabulary.hasSubject(this.getDocumentGraphs(), classIri)) {
			// 	iconName += '-ref';
			// }
 
			if (this.vocabulary.hasIndividuals(this.getDocumentGraphs(), classIri)) {
				iconName += "-i";
			}
		}
 
		return iconName;
	}
 
	/**
	 * Get the icon color of a class depending on its properties in the document graph.
	 * @param classIri IRI of a class.
	 * @returns The icon color of the class.
	 */
	getIconColorFromClass(classIri?: string) {
		return this.getIconColor();
	}
 
	override getIcon(): vscode.ThemeIcon | undefined {
		const iconName = this.getIconNameFromClass(this.uri);
		const iconColor = this.getIconColorFromClass(this.uri);
 
		return new vscode.ThemeIcon(iconName, iconColor);
	}
 
	override getIconColor() {
		return new vscode.ThemeColor("mentor.color.class");
	}
 
	override hasChildren(): boolean {
		for (const _ of this.getSubClassIris()) {
			return true;
		}
 
		if (this.showIndividuals()) {
			for (const _ of this.getIndividualIris()) {
				return true;
			}
		}
 
		return false;
	}
 
	override getChildren() {
		const result = [];
		const classNodes = [];
 
		for (const iri of this.getSubClassIris()) {
			classNodes.push(this.getClassNode(iri));
		}
 
		result.push(...sortByLabel(classNodes));
 
		if (this.showIndividuals()) {
			const individualNodes = [];
 
			for (const iri of this.getIndividualIris()) {
				individualNodes.push(this.getIndividualNode(iri));
			}
 
			result.push(...sortByLabel(individualNodes));
		}
 
		return result;
	}
 
	/**
	 * Get the node of a class instance. Can be overloaded to provide a custom node type.
	 * @param iri IRI of the node.
	 * @returns A node instance.
	 */
	abstract getClassNode(iri: string): DefinitionTreeNode;
 
	/**
	 * Get the node of an individual. Can be overloaded to provide a custom node type.
	 * @param iri IRI of the node.
	 * @returns A node instance.
	 */
	abstract getIndividualNode(iri: string): DefinitionTreeNode;
 
	/**
	 * Get the IRIs of the sub-classes of the class. This method should be overloaded to provide a custom
	 * implementation for specific class types.
	 * @returns An array of sub-class IRIs.
	 */
	*getSubClassIris(): IterableIterator<string> {
		const graphs = this.getOntologyGraphs();
		const options = this.getQueryOptions();
 
		// Note: We are querying the possibly extended ontology graphs here for class relationships.
		yield* this.vocabulary.getSubClasses(graphs, this.uri, options);
	}
 
	/**
	 * Get the IRIs of the individuals of the class. This method should be overloaded to provide a custom
	 * implementation for specific class types.
	 * @returns An array of individual IRIs.
	 */
	*getIndividualIris(): IterableIterator<string> {
		const graphs = this.getDocumentGraphs();
		const options = this.getQueryOptions({ includeSubTypes: false });
 
		// Note: If we set includeSubTypes to `false`, we *must* provide the ontology graphs so that
		// type hierarchies can be loaded and individuals can be filtered accordingly. If this is not done,
		// we will return more individuals than expected.
		yield* this.vocabulary.getSubjectsOfType(graphs, this.uri, options);
	}
}