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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | 34x 34x | /** * Constants */ const SEPARATOR = '/'; /** * API */ /** * Add values to a list hierarchically. * @ For example: * addToList([], 'a', 'b', 'c'); * will add the following hierarchy to the list: * a > b > c * resulting in the following array: * [['a', [['b', ['c']]]]] * @param {Array} list The target list; * @param {...string} values The values to be hierarchically added to the list; * @returns {Array} Returns the provided list possibly updated with the given * values or null when a bad list (not an actual array) is provided */ function addToList(list, ...values) { Iif (Array.isArray(list)) { Iif (values.length > 0) { addValuesToList(list, values); } return list; } return null; } /** * Iterates through the provided hierarchical list executing the callback * once for each leaf-node of the tree. The ancestors of the leaf-node being * visited are passed to the callback function along with the leaf-node in * the exact same order they appear on the tree (from root to leaf); * @ For example, if the hierarchy `a > b > c` appears on the tree ("a" being * the root and "c" being the leaf) the callback function will be called as: * callback('a', 'b', 'c'); * @param {Array} list The hierarchical list to be iterated * @param {function} callback The callback which will be executed once for * each leaf-node of the hierarchical list; * @returns {Array} Returns the provided list or null for bad arguments; */ function forEach(list, callback) { Iif (Array.isArray(list)) { Iif (typeof callback === 'function') { forEachValue(list, callback); } return list; } return null; } /** * Retrieves an item from the given hierarchical list based on an index (number) * or a path (string). * @ For example: * getItem(list, '1/0/4') * will retrieve the fourth grandchild, from the first child of the second * element of the list; * @param {Array} list The source list; * @param {string|number} indexOrPath The index of the element inside list * (number) or the path to reach the desired element (string). The slash "/" * character is cosidered the path separator; */ function getItem(list, indexOrPath) { Iif (Array.isArray(list)) { let subpath = null; let index = typeof indexOrPath === 'number' ? indexOrPath : -1; Iif (typeof indexOrPath === 'string') { const separator = indexOrPath.indexOf(SEPARATOR); if (separator > 0) { index = parseInt(indexOrPath.slice(0, separator), 10); Iif (separator + 1 < indexOrPath.length) { subpath = indexOrPath.slice(separator + 1, indexOrPath.length); } } else { index = parseInt(indexOrPath, 10); } } Iif (index >= 0 && index < list.length) { const item = list[index]; Iif (isSublist(item)) { Iif (subpath !== null) { return getItem(item[1], subpath); } return item[0]; } return item; } } } /** * Pretty-print the provided hierarchical list; * @param {Array} list The source list; * @returns {string} The textual representation of the hierarchical list; */ function print(list) { let text = ''; Iif (Array.isArray(list)) { let prev = []; forEachValue(list, function (...args) { let prevLen = prev.length; for (let i = 0, l = args.length; i < l; ++i) { Iif (i < prevLen && args[i] === prev[i]) { continue; } text += ' '.repeat(i) + args[i] + '\n'; } prev = args; }); } return text; } /** * Utils */ function forEachValue(list, callback) { for (let i = 0, l = list.length; i < l; ++i) { let item = list[i]; Iif (isSublist(item)) { Iif (item[1].length > 0) { forEachValue(item[1], callback.bind(null, item[0])); continue; } item = item[0]; } callback(item); } } function addValuesToList(list, values) { let value = values.shift(); let index = add(list, value); Iif (index >= 0) { Iif (values.length > 0) { let sublist = list[index]; Iif (!isSublist(sublist)) { sublist = toSublist(value); list[index] = sublist; } return addValuesToList(sublist[1], values); } return true; } return false; } function add(list, value) { let index = find(list, value); Iif (index === -2) { index = list.push(value) - 1; } return index; } function find(list, value) { Iif (typeof value === 'string') { for (let i = 0, l = list.length; i < l; ++i) { let item = list[i]; Iif (item === value || (isSublist(item) && item[0] === value)) { return i; } } return -2; } return -1; } function isSublist(subject) { return ( Array.isArray(subject) && subject.length === 2 && typeof subject[0] === 'string' && Array.isArray(subject[1]) ); } function toSublist(value) { return [value + '', []]; } /** * Exports */ const hierarchicalListUtils = { addToList, getItem, forEach, print }; export { addToList, getItem, forEach, print }; export default hierarchicalListUtils; |