UNPKG

graph-explorer

Version:

Graph Explorer can be used to explore and RDF graphs in SPARQL endpoints or on the web.

223 lines (195 loc) 5.18 kB
export function objectValues<T>(obj: Record<string, T>): T[] { const items: T[] = []; for (const key in obj) { if (!Object.prototype.hasOwnProperty.call(obj, key)) { continue; } items.push(obj[key]); } return items; } export function isEmptyMap(map: object) { for (const key in map) { if (Object.prototype.hasOwnProperty.call(map, key)) { return false; } } return true; } /** * Clones Map collection. Required due to IE11 not supporing `new Map(map)`. */ export function cloneMap<K, V>(map: ReadonlyMap<K, V>): Map<K, V> { const clone = new Map<K, V>(); map.forEach((value, key) => clone.set(key, value)); return clone; } /** * Clones Set collection. Required due to IE11 not supporing `new Set(set)`. */ export function cloneSet<T>(set: ReadonlySet<T>): Set<T> { const clone = new Set<T>(); set.forEach((item) => clone.add(item)); return clone; } export function getOrCreateArrayInMap<K, V>(map: Map<K, V[]>, key: K): V[] { let values = map.get(key); if (!values) { values = []; map.set(key, values); } return values; } export function getOrCreateSetInMap<K, V>(map: Map<K, Set<V>>, key: K): Set<V> { let values = map.get(key); if (!values) { values = new Set(); map.set(key, values); } return values; } export class OrderedMap<V> { private mapping = new Map<string, V>(); private ordered: V[] = []; reorder(compare: (a: V, b: V) => number) { this.ordered.sort(compare); } get items(): readonly V[] { return this.ordered; } get(key: string): V | undefined { return this.mapping.get(key); } push(key: string, value: V) { if (this.mapping.has(key)) { const previous = this.mapping.get(key); if (previous === value) { return; } const index = this.ordered.indexOf(previous); this.ordered.splice(index, 1); } this.mapping.set(key, value); this.ordered.push(value); } delete(key: string): V | undefined { if (!this.mapping.has(key)) { return undefined; } const previous = this.mapping.get(key); const index = this.ordered.indexOf(previous); this.ordered.splice(index, 1); this.mapping.delete(key); return previous; } } export interface ReadonlyHashMap<K, V> { readonly size: number; has(key: K): boolean; get(key: K): V | undefined; forEach( callback: (value: V, key: K, map: ReadonlyHashMap<K, V>) => void ): void; clone(): HashMap<K, V>; } export class HashMap<K, V> implements ReadonlyHashMap<K, V> { private readonly map = new Map<number, { key: K; value: V }[]>(); private _size = 0; constructor( private hashCode: (key: K) => number, private equals: (k1: K, k2: K) => boolean ) {} get size() { return this._size; } has(key: K): boolean { const items = this.map.get(this.hashCode(key)); if (!items) { return false; } return Boolean(items.find((p) => this.equals(p.key, key))); } get(key: K): V | undefined { const items = this.map.get(this.hashCode(key)); if (!items) { return undefined; } const pair = items.find((p) => this.equals(p.key, key)); return pair ? pair.value : undefined; } set(key: K, value: V): this { const hash = this.hashCode(key); let items = this.map.get(hash); if (items) { const index = items.findIndex((p) => this.equals(p.key, key)); if (index >= 0) { items.splice(index, 1); } else { this._size++; } items.push({ key, value }); } else { items = [{ key, value }]; this.map.set(hash, items); this._size++; } return this; } delete(key: K): boolean { const items = this.map.get(this.hashCode(key)); if (!items) { return false; } const index = items.findIndex((p) => this.equals(p.key, key)); if (index >= 0) { items.splice(index, 1); this._size--; return true; } else { return false; } } clear(): void { this.map.clear(); this._size = 0; } forEach(callback: (value: V, key: K, map: HashMap<K, V>) => void) { this.map.forEach((items) => { for (const { key, value } of items) { callback(value, key, this); } }); } clone(): HashMap<K, V> { const clone = new HashMap<K, V>(this.hashCode, this.equals); clone._size = this.size; this.map.forEach((value, key) => clone.map.set(key, [...value])); return clone; } } export enum MoveDirection { ToStart = -1, ToEnd = 1, } export function makeMoveComparator<T>( items: readonly T[], selected: readonly T[], moveDirection: MoveDirection ): (a: T, b: T) => number { const orderMap = new Map<T, number>(); const selectionIndexOffset = moveDirection * items.length; items.forEach((item, index) => { orderMap.set(item, index); }); for (const selectedItem of selected) { orderMap.set( selectedItem, selectionIndexOffset + orderMap.get(selectedItem) ); } return (a: T, b: T) => { const orderA = orderMap.get(a); const orderB = orderMap.get(b); return orderA > orderB ? 1 : orderA < orderB ? -1 : 0; }; }