UNPKG

@adaptabletools/adaptable

Version:

Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

279 lines (278 loc) 8.8 kB
const SORT_ASC_REVISION = (p1, p2) => sortAscending(p1.revision, p2.revision); export class DeepMap { static clone(map) { const clone = new DeepMap(); map.visit((pair, keys) => { clone.set(keys, pair.value); }); return clone; } constructor(initial) { this.map = new Map(); this.length = 0; this.revision = 0; this.visit = (fn) => { this.map.forEach((_, k) => this.visitKey(k, this.map, [], fn)); }; this.visitDepthFirst = (fn) => { this.visitWithNext([], fn); }; this.visitWithNext = (parentKeys, fn, currentMap = this.map) => { if (!currentMap) { return; } let i = 0; currentMap.forEach((_, key) => { const pair = currentMap.get(key); if (!pair) { return; } const { map } = pair; const keys = [...parentKeys, key]; const next = map ? () => this.visitWithNext(keys, fn, map) : undefined; if (pair.hasOwnProperty('value')) { fn(pair.value, keys, i, next); i++; } else { next?.(); } }); }; if (initial) { initial.forEach((entry) => { const [keys, value] = entry; this.set(keys, value); }); } } set(keys, value) { let currentMap = this.map; if (!keys.length) { throw `Cannot set given keys - please provide a non-empty keys array.`; // currentMap.set((EMPTY_KEY as unknown) as K, { value }); // this.length++; // return this; } for (let i = 0, len = keys.length; i < len; i++) { const key = keys[i]; const last = i === len - 1; if (last) { const pair = currentMap.has(key) ? currentMap.get(key) : {}; pair.revision = this.revision++; pair.value = value; currentMap.set(key, pair); this.length++; } else { const pair = currentMap.has(key) ? currentMap.get(key) : {}; if (!pair.map) { pair.map = new Map(); currentMap.set(key, pair); } currentMap = pair.map; } } return this; } get(keys) { let currentMap = this.map; if (!keys.length) { throw `Cannot get given keys - please provide a non-empty keys array.`; // return currentMap.get((EMPTY_KEY as unknown) as K)?.value; } for (let i = 0, len = keys.length; i < len; i++) { const key = keys[i]; const last = i === len - 1; if (last) { return currentMap.get(key)?.value; } else { const pair = currentMap.get(key); if (!pair || !pair.map) { return; } currentMap = pair.map; } } return; } get size() { return this.length; } clear() { const clearMap = (map) => { map.forEach((value, _key) => { const { map } = value; if (map) { clearMap(map); } }); map.clear(); }; clearMap(this.map); this.length = 0; this.revision = 0; } delete(keys) { keys = [...keys]; let currentMap = this.map; if (!keys.length) { throw `Cannot delete given keys - please provide a non-empty keys array.`; // if (currentMap.has(EMPTY_KEY as unknown as K)) { // this.length--; // } // return currentMap.delete((EMPTY_KEY as unknown) as K); } let maps = [currentMap]; let result = false; for (let i = 0, len = keys.length; i < len; i++) { const key = keys[i]; const last = i === len - 1; if (last) { const pair = currentMap.get(key); if (pair) { if (pair.hasOwnProperty('value')) { delete pair.value; delete pair.revision; result = true; this.length--; } if (pair.map && pair.map.size === 0) { delete pair.map; } if (!pair.map) { // pair is empty, so we can remove it altogether currentMap.delete(key); } } break; } else { const pair = currentMap.get(key); if (!pair || !pair.map) { result = false; break; } currentMap = pair.map; maps.push(currentMap); } } while (maps.length) { let map = maps.pop(); let key = keys.pop(); if (key && map?.size === 0) { let parentMap = maps[maps.length - 1]; let pair = parentMap?.get(key); if (pair) { // pair.map === map ; which can be deleted delete pair.map; if (!pair.hasOwnProperty('value')) { // whole pair can be successfully deleted from parentMap parentMap.delete(key); } } } } return result; } has(keys) { let currentMap = this.map; if (!keys.length) { throw `Cannot find existing given keys - please provide a non-empty keys array.`; // return ( // currentMap.has((EMPTY_KEY as unknown) as K) && // currentMap.get((EMPTY_KEY as unknown) as K)?.value !== undefined // ); } for (let i = 0, len = keys.length; i < len; i++) { const key = keys[i]; const last = i === len - 1; if (last) { const pair = currentMap.get(key); return !!pair && pair.hasOwnProperty('value'); } else { const pair = currentMap.get(key); if (!pair || !pair.map) { return false; } currentMap = pair.map; } } return false; } visitKey(key, currentMap, parentKeys, fn) { const pair = currentMap.get(key); if (!pair) { return; } const { map } = pair; const keys = [...parentKeys, key]; const next = once(() => { if (map) { map.forEach((_, k) => { this.visitKey(k, map, keys, fn); }); } }); if (pair.hasOwnProperty('value')) { fn(pair, keys, next); } // if it was called by fn, it won't be called again, as it's once-d next(); } getArray(fn) { const result = []; this.visit((pair, keys) => { result.push(fn({ ...pair, keys })); }); return result; } values() { return this.sortedIterator((pair) => pair.value); } keys() { const keys = this.sortedIterator((pair) => pair.keys); return keys; } entries() { return this.sortedIterator((pair) => [pair.keys, pair.value]); } topDownEntries() { return this.getArray((pair) => [pair.keys, pair.value]); } topDownKeys() { return this.getArray((pair) => pair.keys); } topDownValues() { return this.getArray((pair) => pair.value); } sortedIterator(fn) { const result = []; this.visit((pair, keys) => { result.push({ ...pair, keys }); }); result.sort(SORT_ASC_REVISION); function* makeIterator() { for (let i = 0, len = result.length; i < len; i++) { yield fn(result[i]); } } return makeIterator(); } } export function once(fn) { let called = false; let result = null; const onceFn = () => { if (called) { return result; } called = true; result = fn(); return result; }; return onceFn; } const sortAscending = (a, b) => a - b;