UNPKG

@speckle/shared

Version:

Shared code between various Speckle JS packages

139 lines 5.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.xor = exports.waitForever = exports.isArrayOf = exports.coerceUndefinedValuesToNull = exports.removeNullOrUndefinedKeys = exports.profileSync = exports.profile = exports.retry = exports.timeoutAt = exports.isNonNullable = exports.waitIntervalUntil = exports.wait = exports.isNullOrUndefined = exports.buildManualPromise = exports.WaitIntervalUntilCanceledError = exports.TimeoutError = void 0; const _lodash_1 = require("#lodash"); const error_js_1 = require("./error.js"); class TimeoutError extends Error { } exports.TimeoutError = TimeoutError; class WaitIntervalUntilCanceledError extends Error { } exports.WaitIntervalUntilCanceledError = WaitIntervalUntilCanceledError; /** * Build promise that can be resolved/rejected manually outside of the promise's execution scope */ const buildManualPromise = () => { let resolve; // eslint-disable-next-line @typescript-eslint/no-explicit-any let reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); const resolveWrapper = (...args) => resolve(...args); const rejectWrapper = (...args) => reject(...args); return { promise, resolve: resolveWrapper, reject: rejectWrapper }; }; exports.buildManualPromise = buildManualPromise; const isNullOrUndefined = (val) => (0, _lodash_1.isNull)(val) || (0, _lodash_1.isUndefined)(val); exports.isNullOrUndefined = isNullOrUndefined; const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); exports.wait = wait; const waitIntervalUntil = (ms, predicate) => { const { promise, resolve, reject } = (0, exports.buildManualPromise)(); const interval = setInterval(() => { if (predicate()) { clearInterval(interval); resolve(); } }, ms); const ret = promise; ret.cancel = () => { clearInterval(interval); reject(new WaitIntervalUntilCanceledError()); }; return ret; }; exports.waitIntervalUntil = waitIntervalUntil; /** * Not nullable type guard, useful in `.filter()` calls for proper TS typed * results */ const isNonNullable = (v) => !!v; exports.isNonNullable = isNonNullable; /** * Make the promise throw after enough time has passed. Useful for implementing timeout functionality in various flows. */ const timeoutAt = (ms, optionalMessage) => { // create error beforehand, so we have a better stack trace const err = new TimeoutError(optionalMessage || 'timeoutAt() timed out'); return new Promise((_resolve, reject) => setTimeout(() => { reject(err); }, ms)); }; exports.timeoutAt = timeoutAt; /** * Invoke and return fn(), but retry it up to n times if it throws */ const retry = async (fn, n, delayMs) => { let lastError; for (let i = 0; i < n; i++) { try { const res = await Promise.resolve(fn()); return res; } catch (error) { lastError = (0, error_js_1.ensureError)(error); if (delayMs && i + 1 < n) { if ((0, _lodash_1.isNumber)(delayMs)) { await (0, exports.wait)(delayMs); } else { await (0, exports.wait)(delayMs(i + 1, lastError)); } } } } throw lastError || new Error('Unexpected retry() failure'); }; exports.retry = retry; /** * For quickly profiling a function */ const profile = async (fn, label, extra) => { const start = performance.now(); const res = await Promise.resolve(fn()); const end = performance.now(); console.log(`[${label || 'profile'}] took ${end - start}ms`, ...(extra ? [extra] : [])); return res; }; exports.profile = profile; /** * For quickly profiling a sync function */ const profileSync = (fn, label, extra) => { const start = performance.now(); const res = fn(); const end = performance.now(); console.log(`[${label || 'profile'}] took ${end - start}ms`, ...(extra ? [extra] : [])); return res; }; exports.profileSync = profileSync; const removeNullOrUndefinedKeys = (obj) => { const ret = {}; for (const key in obj) { if (!(0, exports.isNullOrUndefined)(obj[key])) { ret[key] = obj[key]; } } return ret; }; exports.removeNullOrUndefinedKeys = removeNullOrUndefinedKeys; const coerceUndefinedValuesToNull = (obj) => { const ret = {}; for (const [key, value] of Object.entries(obj)) { ret[key] = (0, _lodash_1.isUndefined)(value) ? null : value; } return ret; }; exports.coerceUndefinedValuesToNull = coerceUndefinedValuesToNull; const isArrayOf = (arr, guard) => Array.isArray(arr) && arr.every(guard); exports.isArrayOf = isArrayOf; const waitForever = () => new Promise(_lodash_1.noop); exports.waitForever = waitForever; /** * Returns true if only one of the arguments is truthy */ const xor = (a, b) => !!((a || b) && !(a && b)); exports.xor = xor; //# sourceMappingURL=utility.js.map