/** * Debounce a function to delay invoking until wait (ms) have elapsed since the last invocation. * @param {function(...*): *} fn The function to be debounced. * @param {number} wait Milliseconds to wait before invoking again. * @return {function(...*): void} The debounced function. */ function debounce(fn, wait) { /** * A cached setTimeout handler. * @type {number | undefined} */ let timer; /** * @returns {void} */ function debounced() { const context = this; const args = arguments; clearTimeout(timer); timer = setTimeout(function () { return fn.apply(context, args); }, wait); } return debounced; } /** * Prettify a filename from error stacks into the desired format. * @param {string} filename The filename to be formatted. * @returns {string} The formatted filename. */ function formatFilename(filename) { // Strip away protocol and domain for compiled files const htmlMatch = /^https?:\/\/(.*)\/(.*)/.exec(filename); if (htmlMatch && htmlMatch[1] && htmlMatch[2]) { return htmlMatch[2]; } // Strip everything before the first directory for source files const sourceMatch = /\/.*?([^./]+[/|\\].*)$/.exec(filename); if (sourceMatch && sourceMatch[1]) { return sourceMatch[1].replace(/\?$/, ''); } // Unknown filename type, use it as is return filename; } /** * Remove all children of an element. * @param {HTMLElement} element A valid HTML element. * @param {number} [skip] Number of elements to skip removing. * @returns {void} */ function removeAllChildren(element, skip) { /** @type {Node[]} */ const childList = Array.prototype.slice.call( element.childNodes, typeof skip !== 'undefined' ? skip : 0 ); for (let i = 0; i < childList.length; i += 1) { element.removeChild(childList[i]); } } module.exports = { debounce: debounce, formatFilename: formatFilename, removeAllChildren: removeAllChildren, };