diff options
| author | Joel Kronqvist <joel.h.kronqvist@gmail.com> | 2022-03-05 19:02:27 +0200 | 
|---|---|---|
| committer | Joel Kronqvist <joel.h.kronqvist@gmail.com> | 2022-03-05 19:02:27 +0200 | 
| commit | 5d309ff52cd399a6b71968a6b9a70c8ac0b98981 (patch) | |
| tree | 360f7eb50f956e2367ef38fa1fc6ac7ac5258042 /node_modules/@sinonjs/fake-timers/src | |
| parent | b500a50f1b97d93c98b36ed9a980f8188d648147 (diff) | |
| download | LYLLRuoka-5d309ff52cd399a6b71968a6b9a70c8ac0b98981.tar.gz LYLLRuoka-5d309ff52cd399a6b71968a6b9a70c8ac0b98981.zip  | |
Added node_modules for the updating to work properly.
Diffstat (limited to 'node_modules/@sinonjs/fake-timers/src')
| -rw-r--r-- | node_modules/@sinonjs/fake-timers/src/fake-timers-src.js | 1728 | 
1 files changed, 1728 insertions, 0 deletions
diff --git a/node_modules/@sinonjs/fake-timers/src/fake-timers-src.js b/node_modules/@sinonjs/fake-timers/src/fake-timers-src.js new file mode 100644 index 0000000..e1a0a1e --- /dev/null +++ b/node_modules/@sinonjs/fake-timers/src/fake-timers-src.js @@ -0,0 +1,1728 @@ +"use strict"; + +const globalObject = require("@sinonjs/commons").global; + +/** + * @typedef {object} IdleDeadline + * @property {boolean} didTimeout - whether or not the callback was called before reaching the optional timeout + * @property {function():number} timeRemaining - a floating-point value providing an estimate of the number of milliseconds remaining in the current idle period + */ + +/** + * Queues a function to be called during a browser's idle periods + * + * @callback RequestIdleCallback + * @param {function(IdleDeadline)} callback + * @param {{timeout: number}} options - an options object + * @returns {number} the id + */ + +/** + * @callback NextTick + * @param {VoidVarArgsFunc} callback - the callback to run + * @param {...*} arguments - optional arguments to call the callback with + * @returns {void} + */ + +/** + * @callback SetImmediate + * @param {VoidVarArgsFunc} callback - the callback to run + * @param {...*} arguments - optional arguments to call the callback with + * @returns {NodeImmediate} + */ + +/** + * @callback VoidVarArgsFunc + * @param {...*} callback - the callback to run + * @returns {void} + */ + +/** + * @typedef RequestAnimationFrame + * @property {function(number):void} requestAnimationFrame + * @returns {number} - the id + */ + +/** + * @typedef Performance + * @property {function(): number} now + */ + +/* eslint-disable jsdoc/require-property-description */ +/** + * @typedef {object} Clock + * @property {number} now - the current time + * @property {Date} Date - the Date constructor + * @property {number} loopLimit - the maximum number of timers before assuming an infinite loop + * @property {RequestIdleCallback} requestIdleCallback + * @property {function(number):void} cancelIdleCallback + * @property {setTimeout} setTimeout + * @property {clearTimeout} clearTimeout + * @property {NextTick} nextTick + * @property {queueMicrotask} queueMicrotask + * @property {setInterval} setInterval + * @property {clearInterval} clearInterval + * @property {SetImmediate} setImmediate + * @property {function(NodeImmediate):void} clearImmediate + * @property {function():number} countTimers + * @property {RequestAnimationFrame} requestAnimationFrame + * @property {function(number):void} cancelAnimationFrame + * @property {function():void} runMicrotasks + * @property {function(string | number): number} tick + * @property {function(string | number): Promise<number>} tickAsync + * @property {function(): number} next + * @property {function(): Promise<number>} nextAsync + * @property {function(): number} runAll + * @property {function(): number} runToFrame + * @property {function(): Promise<number>} runAllAsync + * @property {function(): number} runToLast + * @property {function(): Promise<number>} runToLastAsync + * @property {function(): void} reset + * @property {function(number | Date): void} setSystemTime + * @property {Performance} performance + * @property {function(number[]): number[]} hrtime - process.hrtime (legacy) + * @property {function(): void} uninstall Uninstall the clock. + * @property {Function[]} methods - the methods that are faked + * @property {boolean} [shouldClearNativeTimers] inherited from config + */ +/* eslint-enable jsdoc/require-property-description */ + +/** + * Configuration object for the `install` method. + * + * @typedef {object} Config + * @property {number|Date} [now] a number (in milliseconds) or a Date object (default epoch) + * @property {string[]} [toFake] names of the methods that should be faked. + * @property {number} [loopLimit] the maximum number of timers that will be run when calling runAll() + * @property {boolean} [shouldAdvanceTime] tells FakeTimers to increment mocked time automatically (default false) + * @property {number} [advanceTimeDelta] increment mocked time every <<advanceTimeDelta>> ms (default: 20ms) + * @property {boolean} [shouldClearNativeTimers] forwards clear timer calls to native functions if they are not fakes (default: false) + */ + +/* eslint-disable jsdoc/require-property-description */ +/** + * The internal structure to describe a scheduled fake timer + * + * @typedef {object} Timer + * @property {Function} func + * @property {*[]} args + * @property {number} delay + * @property {number} callAt + * @property {number} createdAt + * @property {boolean} immediate + * @property {number} id + * @property {Error} [error] + */ + +/** + * A Node timer + * + * @typedef {object} NodeImmediate + * @property {function(): boolean} hasRef + * @property {function(): NodeImmediate} ref + * @property {function(): NodeImmediate} unref + */ +/* eslint-enable jsdoc/require-property-description */ + +/* eslint-disable complexity */ + +/** + * Mocks available features in the specified global namespace. + * + * @param {*} _global Namespace to mock (e.g. `window`) + * @returns {FakeTimers} + */ +function withGlobal(_global) { +    const userAgent = _global.navigator && _global.navigator.userAgent; +    const isRunningInIE = userAgent && userAgent.indexOf("MSIE ") > -1; +    const maxTimeout = Math.pow(2, 31) - 1; //see https://heycam.github.io/webidl/#abstract-opdef-converttoint +    const idCounterStart = 1e12; // arbitrarily large number to avoid collisions with native timer IDs +    const NOOP = function () { +        return undefined; +    }; +    const NOOP_ARRAY = function () { +        return []; +    }; +    const timeoutResult = _global.setTimeout(NOOP, 0); +    const addTimerReturnsObject = typeof timeoutResult === "object"; +    const hrtimePresent = +        _global.process && typeof _global.process.hrtime === "function"; +    const hrtimeBigintPresent = +        hrtimePresent && typeof _global.process.hrtime.bigint === "function"; +    const nextTickPresent = +        _global.process && typeof _global.process.nextTick === "function"; +    const utilPromisify = _global.process && require("util").promisify; +    const performancePresent = +        _global.performance && typeof _global.performance.now === "function"; +    const hasPerformancePrototype = +        _global.Performance && +        (typeof _global.Performance).match(/^(function|object)$/); +    const queueMicrotaskPresent = _global.hasOwnProperty("queueMicrotask"); +    const requestAnimationFramePresent = +        _global.requestAnimationFrame && +        typeof _global.requestAnimationFrame === "function"; +    const cancelAnimationFramePresent = +        _global.cancelAnimationFrame && +        typeof _global.cancelAnimationFrame === "function"; +    const requestIdleCallbackPresent = +        _global.requestIdleCallback && +        typeof _global.requestIdleCallback === "function"; +    const cancelIdleCallbackPresent = +        _global.cancelIdleCallback && +        typeof _global.cancelIdleCallback === "function"; +    const setImmediatePresent = +        _global.setImmediate && typeof _global.setImmediate === "function"; + +    // Make properties writable in IE, as per +    // https://www.adequatelygood.com/Replacing-setTimeout-Globally.html +    /* eslint-disable no-self-assign */ +    if (isRunningInIE) { +        _global.setTimeout = _global.setTimeout; +        _global.clearTimeout = _global.clearTimeout; +        _global.setInterval = _global.setInterval; +        _global.clearInterval = _global.clearInterval; +        _global.Date = _global.Date; +    } + +    // setImmediate is not a standard function +    // avoid adding the prop to the window object if not present +    if (setImmediatePresent) { +        _global.setImmediate = _global.setImmediate; +        _global.clearImmediate = _global.clearImmediate; +    } +    /* eslint-enable no-self-assign */ + +    _global.clearTimeout(timeoutResult); + +    const NativeDate = _global.Date; +    let uniqueTimerId = idCounterStart; + +    /** +     * @param {number} num +     * @returns {boolean} +     */ +    function isNumberFinite(num) { +        if (Number.isFinite) { +            return Number.isFinite(num); +        } + +        return isFinite(num); +    } + +    let isNearInfiniteLimit = false; + +    /** +     * @param {Clock} clock +     * @param {number} i +     */ +    function checkIsNearInfiniteLimit(clock, i) { +        if (clock.loopLimit && i === clock.loopLimit - 1) { +            isNearInfiniteLimit = true; +        } +    } + +    /** +     * +     */ +    function resetIsNearInfiniteLimit() { +        isNearInfiniteLimit = false; +    } + +    /** +     * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into +     * number of milliseconds. This is used to support human-readable strings passed +     * to clock.tick() +     * +     * @param {string} str +     * @returns {number} +     */ +    function parseTime(str) { +        if (!str) { +            return 0; +        } + +        const strings = str.split(":"); +        const l = strings.length; +        let i = l; +        let ms = 0; +        let parsed; + +        if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { +            throw new Error( +                "tick only understands numbers, 'm:s' and 'h:m:s'. Each part must be two digits" +            ); +        } + +        while (i--) { +            parsed = parseInt(strings[i], 10); + +            if (parsed >= 60) { +                throw new Error(`Invalid time ${str}`); +            } + +            ms += parsed * Math.pow(60, l - i - 1); +        } + +        return ms * 1000; +    } + +    /** +     * Get the decimal part of the millisecond value as nanoseconds +     * +     * @param {number} msFloat the number of milliseconds +     * @returns {number} an integer number of nanoseconds in the range [0,1e6) +     * +     * Example: nanoRemainer(123.456789) -> 456789 +     */ +    function nanoRemainder(msFloat) { +        const modulo = 1e6; +        const remainder = (msFloat * 1e6) % modulo; +        const positiveRemainder = +            remainder < 0 ? remainder + modulo : remainder; + +        return Math.floor(positiveRemainder); +    } + +    /** +     * Used to grok the `now` parameter to createClock. +     * +     * @param {Date|number} epoch the system time +     * @returns {number} +     */ +    function getEpoch(epoch) { +        if (!epoch) { +            return 0; +        } +        if (typeof epoch.getTime === "function") { +            return epoch.getTime(); +        } +        if (typeof epoch === "number") { +            return epoch; +        } +        throw new TypeError("now should be milliseconds since UNIX epoch"); +    } + +    /** +     * @param {number} from +     * @param {number} to +     * @param {Timer} timer +     * @returns {boolean} +     */ +    function inRange(from, to, timer) { +        return timer && timer.callAt >= from && timer.callAt <= to; +    } + +    /** +     * @param {Clock} clock +     * @param {Timer} job +     */ +    function getInfiniteLoopError(clock, job) { +        const infiniteLoopError = new Error( +            `Aborting after running ${clock.loopLimit} timers, assuming an infinite loop!` +        ); + +        if (!job.error) { +            return infiniteLoopError; +        } + +        // pattern never matched in Node +        const computedTargetPattern = /target\.*[<|(|[].*?[>|\]|)]\s*/; +        let clockMethodPattern = new RegExp( +            String(Object.keys(clock).join("|")) +        ); + +        if (addTimerReturnsObject) { +            // node.js environment +            clockMethodPattern = new RegExp( +                `\\s+at (Object\\.)?(?:${Object.keys(clock).join("|")})\\s+` +            ); +        } + +        let matchedLineIndex = -1; +        job.error.stack.split("\n").some(function (line, i) { +            // If we've matched a computed target line (e.g. setTimeout) then we +            // don't need to look any further. Return true to stop iterating. +            const matchedComputedTarget = line.match(computedTargetPattern); +            /* istanbul ignore if */ +            if (matchedComputedTarget) { +                matchedLineIndex = i; +                return true; +            } + +            // If we've matched a clock method line, then there may still be +            // others further down the trace. Return false to keep iterating. +            const matchedClockMethod = line.match(clockMethodPattern); +            if (matchedClockMethod) { +                matchedLineIndex = i; +                return false; +            } + +            // If we haven't matched anything on this line, but we matched +            // previously and set the matched line index, then we can stop. +            // If we haven't matched previously, then we should keep iterating. +            return matchedLineIndex >= 0; +        }); + +        const stack = `${infiniteLoopError}\n${job.type || "Microtask"} - ${ +            job.func.name || "anonymous" +        }\n${job.error.stack +            .split("\n") +            .slice(matchedLineIndex + 1) +            .join("\n")}`; + +        try { +            Object.defineProperty(infiniteLoopError, "stack", { +                value: stack, +            }); +        } catch (e) { +            // noop +        } + +        return infiniteLoopError; +    } + +    /** +     * @param {Date} target +     * @param {Date} source +     * @returns {Date} the target after modifications +     */ +    function mirrorDateProperties(target, source) { +        let prop; +        for (prop in source) { +            if (source.hasOwnProperty(prop)) { +                target[prop] = source[prop]; +            } +        } + +        // set special now implementation +        if (source.now) { +            target.now = function now() { +                return target.clock.now; +            }; +        } else { +            delete target.now; +        } + +        // set special toSource implementation +        if (source.toSource) { +            target.toSource = function toSource() { +                return source.toSource(); +            }; +        } else { +            delete target.toSource; +        } + +        // set special toString implementation +        target.toString = function toString() { +            return source.toString(); +        }; + +        target.prototype = source.prototype; +        target.parse = source.parse; +        target.UTC = source.UTC; +        target.prototype.toUTCString = source.prototype.toUTCString; + +        return target; +    } + +    //eslint-disable-next-line jsdoc/require-jsdoc +    function createDate() { +        /** +         * @param {number} year +         * @param {number} month +         * @param {number} date +         * @param {number} hour +         * @param {number} minute +         * @param {number} second +         * @param {number} ms +         * +         * @returns {Date} +         */ +        function ClockDate(year, month, date, hour, minute, second, ms) { +            // the Date constructor called as a function, ref Ecma-262 Edition 5.1, section 15.9.2. +            // This remains so in the 10th edition of 2019 as well. +            if (!(this instanceof ClockDate)) { +                return new NativeDate(ClockDate.clock.now).toString(); +            } + +            // if Date is called as a constructor with 'new' keyword +            // Defensive and verbose to avoid potential harm in passing +            // explicit undefined when user does not pass argument +            switch (arguments.length) { +                case 0: +                    return new NativeDate(ClockDate.clock.now); +                case 1: +                    return new NativeDate(year); +                case 2: +                    return new NativeDate(year, month); +                case 3: +                    return new NativeDate(year, month, date); +                case 4: +                    return new NativeDate(year, month, date, hour); +                case 5: +                    return new NativeDate(year, month, date, hour, minute); +                case 6: +                    return new NativeDate( +                        year, +                        month, +                        date, +                        hour, +                        minute, +                        second +                    ); +                default: +                    return new NativeDate( +                        year, +                        month, +                        date, +                        hour, +                        minute, +                        second, +                        ms +                    ); +            } +        } + +        return mirrorDateProperties(ClockDate, NativeDate); +    } + +    //eslint-disable-next-line jsdoc/require-jsdoc +    function enqueueJob(clock, job) { +        // enqueues a microtick-deferred task - ecma262/#sec-enqueuejob +        if (!clock.jobs) { +            clock.jobs = []; +        } +        clock.jobs.push(job); +    } + +    //eslint-disable-next-line jsdoc/require-jsdoc +    function runJobs(clock) { +        // runs all microtick-deferred tasks - ecma262/#sec-runjobs +        if (!clock.jobs) { +            return; +        } +        for (let i = 0; i < clock.jobs.length; i++) { +            const job = clock.jobs[i]; +            job.func.apply(null, job.args); + +            checkIsNearInfiniteLimit(clock, i); +            if (clock.loopLimit && i > clock.loopLimit) { +                throw getInfiniteLoopError(clock, job); +            } +        } +        resetIsNearInfiniteLimit(); +        clock.jobs = []; +    } + +    /** +     * @param {Clock} clock +     * @param {Timer} timer +     * @returns {number} id of the created timer +     */ +    function addTimer(clock, timer) { +        if (timer.func === undefined) { +            throw new Error("Callback must be provided to timer calls"); +        } + +        if (addTimerReturnsObject) { +            // Node.js environment +            if (typeof timer.func !== "function") { +                throw new TypeError( +                    `[ERR_INVALID_CALLBACK]: Callback must be a function. Received ${ +                        timer.func +                    } of type ${typeof timer.func}` +                ); +            } +        } + +        if (isNearInfiniteLimit) { +            timer.error = new Error(); +        } + +        timer.type = timer.immediate ? "Immediate" : "Timeout"; + +        if (timer.hasOwnProperty("delay")) { +            if (typeof timer.delay !== "number") { +                timer.delay = parseInt(timer.delay, 10); +            } + +            if (!isNumberFinite(timer.delay)) { +                timer.delay = 0; +            } +            timer.delay = timer.delay > maxTimeout ? 1 : timer.delay; +            timer.delay = Math.max(0, timer.delay); +        } + +        if (timer.hasOwnProperty("interval")) { +            timer.type = "Interval"; +            timer.interval = timer.interval > maxTimeout ? 1 : timer.interval; +        } + +        if (timer.hasOwnProperty("animation")) { +            timer.type = "AnimationFrame"; +            timer.animation = true; +        } + +        if (timer.hasOwnProperty("idleCallback")) { +            timer.type = "IdleCallback"; +            timer.idleCallback = true; +        } + +        if (!clock.timers) { +            clock.timers = {}; +        } + +        timer.id = uniqueTimerId++; +        timer.createdAt = clock.now; +        timer.callAt = +            clock.now + (parseInt(timer.delay) || (clock.duringTick ? 1 : 0)); + +        clock.timers[timer.id] = timer; + +        if (addTimerReturnsObject) { +            const res = { +                ref: function () { +                    return res; +                }, +                unref: function () { +                    return res; +                }, +                refresh: function () { +                    clearTimeout(timer.id); +                    const args = [timer.func, timer.delay].concat(timer.args); +                    return setTimeout.apply(null, args); +                }, +                [Symbol.toPrimitive]: function () { +                    return timer.id; +                }, +            }; +            return res; +        } + +        return timer.id; +    } + +    /* eslint consistent-return: "off" */ +    /** +     * Timer comparitor +     * +     * @param {Timer} a +     * @param {Timer} b +     * @returns {number} +     */ +    function compareTimers(a, b) { +        // Sort first by absolute timing +        if (a.callAt < b.callAt) { +            return -1; +        } +        if (a.callAt > b.callAt) { +            return 1; +        } + +        // Sort next by immediate, immediate timers take precedence +        if (a.immediate && !b.immediate) { +            return -1; +        } +        if (!a.immediate && b.immediate) { +            return 1; +        } + +        // Sort next by creation time, earlier-created timers take precedence +        if (a.createdAt < b.createdAt) { +            return -1; +        } +        if (a.createdAt > b.createdAt) { +            return 1; +        } + +        // Sort next by id, lower-id timers take precedence +        if (a.id < b.id) { +            return -1; +        } +        if (a.id > b.id) { +            return 1; +        } + +        // As timer ids are unique, no fallback `0` is necessary +    } + +    /** +     * @param {Clock} clock +     * @param {number} from +     * @param {number} to +     * +     * @returns {Timer} +     */ +    function firstTimerInRange(clock, from, to) { +        const timers = clock.timers; +        let timer = null; +        let id, isInRange; + +        for (id in timers) { +            if (timers.hasOwnProperty(id)) { +                isInRange = inRange(from, to, timers[id]); + +                if ( +                    isInRange && +                    (!timer || compareTimers(timer, timers[id]) === 1) +                ) { +                    timer = timers[id]; +                } +            } +        } + +        return timer; +    } + +    /** +     * @param {Clock} clock +     * @returns {Timer} +     */ +    function firstTimer(clock) { +        const timers = clock.timers; +        let timer = null; +        let id; + +        for (id in timers) { +            if (timers.hasOwnProperty(id)) { +                if (!timer || compareTimers(timer, timers[id]) === 1) { +                    timer = timers[id]; +                } +            } +        } + +        return timer; +    } + +    /** +     * @param {Clock} clock +     * @returns {Timer} +     */ +    function lastTimer(clock) { +        const timers = clock.timers; +        let timer = null; +        let id; + +        for (id in timers) { +            if (timers.hasOwnProperty(id)) { +                if (!timer || compareTimers(timer, timers[id]) === -1) { +                    timer = timers[id]; +                } +            } +        } + +        return timer; +    } + +    /** +     * @param {Clock} clock +     * @param {Timer} timer +     */ +    function callTimer(clock, timer) { +        if (typeof timer.interval === "number") { +            clock.timers[timer.id].callAt += timer.interval; +        } else { +            delete clock.timers[timer.id]; +        } + +        if (typeof timer.func === "function") { +            timer.func.apply(null, timer.args); +        } else { +            /* eslint no-eval: "off" */ +            const eval2 = eval; +            (function () { +                eval2(timer.func); +            })(); +        } +    } + +    /** +     * Gets clear handler name for a given timer type +     * @param {string} ttype +     */ +    function getClearHandler(ttype) { +        if (ttype === "IdleCallback" || ttype === "AnimationFrame") { +            return `cancel${ttype}`; +        } +        return `clear${ttype}`; +    } + +    /** +     * Gets schedule handler name for a given timer type +     * @param {string} ttype +     */ +    function getScheduleHandler(ttype) { +        if (ttype === "IdleCallback" || ttype === "AnimationFrame") { +            return `request${ttype}`; +        } +        return `set${ttype}`; +    } + +    /** +     * Creates an anonymous function to warn only once +     */ +    function createWarnOnce() { +        let calls = 0; +        return function (msg) { +            // eslint-disable-next-line +            !calls++ && console.warn(msg); +        }; +    } +    const warnOnce = createWarnOnce(); + +    /** +     * @param {Clock} clock +     * @param {number} timerId +     * @param {string} ttype +     */ +    function clearTimer(clock, timerId, ttype) { +        if (!timerId) { +            // null appears to be allowed in most browsers, and appears to be +            // relied upon by some libraries, like Bootstrap carousel +            return; +        } + +        if (!clock.timers) { +            clock.timers = {}; +        } + +        // in Node, the ID is stored as the primitive value for `Timeout` objects +        // for `Immediate` objects, no ID exists, so it gets coerced to NaN +        const id = Number(timerId); + +        if (Number.isNaN(id) || id < idCounterStart) { +            const handlerName = getClearHandler(ttype); + +            if (clock.shouldClearNativeTimers === true) { +                const nativeHandler = clock[`_${handlerName}`]; +                return typeof nativeHandler === "function" +                    ? nativeHandler(timerId) +                    : undefined; +            } +            warnOnce( +                `FakeTimers: ${handlerName} was invoked to clear a native timer instead of one created by this library.` + +                    "\nTo automatically clean-up native timers, use `shouldClearNativeTimers`." +            ); +        } + +        if (clock.timers.hasOwnProperty(id)) { +            // check that the ID matches a timer of the correct type +            const timer = clock.timers[id]; +            if ( +                timer.type === ttype || +                (timer.type === "Timeout" && ttype === "Interval") || +                (timer.type === "Interval" && ttype === "Timeout") +            ) { +                delete clock.timers[id]; +            } else { +                const clear = getClearHandler(ttype); +                const schedule = getScheduleHandler(timer.type); +                throw new Error( +                    `Cannot clear timer: timer created with ${schedule}() but cleared with ${clear}()` +                ); +            } +        } +    } + +    /** +     * @param {Clock} clock +     * @param {Config} config +     * @returns {Timer[]} +     */ +    function uninstall(clock, config) { +        let method, i, l; +        const installedHrTime = "_hrtime"; +        const installedNextTick = "_nextTick"; + +        for (i = 0, l = clock.methods.length; i < l; i++) { +            method = clock.methods[i]; +            if (method === "hrtime" && _global.process) { +                _global.process.hrtime = clock[installedHrTime]; +            } else if (method === "nextTick" && _global.process) { +                _global.process.nextTick = clock[installedNextTick]; +            } else if (method === "performance") { +                const originalPerfDescriptor = Object.getOwnPropertyDescriptor( +                    clock, +                    `_${method}` +                ); +                if ( +                    originalPerfDescriptor && +                    originalPerfDescriptor.get && +                    !originalPerfDescriptor.set +                ) { +                    Object.defineProperty( +                        _global, +                        method, +                        originalPerfDescriptor +                    ); +                } else if (originalPerfDescriptor.configurable) { +                    _global[method] = clock[`_${method}`]; +                } +            } else { +                if (_global[method] && _global[method].hadOwnProperty) { +                    _global[method] = clock[`_${method}`]; +                } else { +                    try { +                        delete _global[method]; +                    } catch (ignore) { +                        /* eslint no-empty: "off" */ +                    } +                } +            } +        } + +        if (config.shouldAdvanceTime === true) { +            _global.clearInterval(clock.attachedInterval); +        } + +        // Prevent multiple executions which will completely remove these props +        clock.methods = []; + +        // return pending timers, to enable checking what timers remained on uninstall +        if (!clock.timers) { +            return []; +        } +        return Object.keys(clock.timers).map(function mapper(key) { +            return clock.timers[key]; +        }); +    } + +    /** +     * @param {object} target the target containing the method to replace +     * @param {string} method the keyname of the method on the target +     * @param {Clock} clock +     */ +    function hijackMethod(target, method, clock) { +        clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call( +            target, +            method +        ); +        clock[`_${method}`] = target[method]; + +        if (method === "Date") { +            const date = mirrorDateProperties(clock[method], target[method]); +            target[method] = date; +        } else if (method === "performance") { +            const originalPerfDescriptor = Object.getOwnPropertyDescriptor( +                target, +                method +            ); +            // JSDOM has a read only performance field so we have to save/copy it differently +            if ( +                originalPerfDescriptor && +                originalPerfDescriptor.get && +                !originalPerfDescriptor.set +            ) { +                Object.defineProperty( +                    clock, +                    `_${method}`, +                    originalPerfDescriptor +                ); + +                const perfDescriptor = Object.getOwnPropertyDescriptor( +                    clock, +                    method +                ); +                Object.defineProperty(target, method, perfDescriptor); +            } else { +                target[method] = clock[method]; +            } +        } else { +            target[method] = function () { +                return clock[method].apply(clock, arguments); +            }; + +            Object.defineProperties( +                target[method], +                Object.getOwnPropertyDescriptors(clock[method]) +            ); +        } + +        target[method].clock = clock; +    } + +    /** +     * @param {Clock} clock +     * @param {number} advanceTimeDelta +     */ +    function doIntervalTick(clock, advanceTimeDelta) { +        clock.tick(advanceTimeDelta); +    } + +    /** +     * @typedef {object} Timers +     * @property {setTimeout} setTimeout +     * @property {clearTimeout} clearTimeout +     * @property {setInterval} setInterval +     * @property {clearInterval} clearInterval +     * @property {Date} Date +     * @property {SetImmediate=} setImmediate +     * @property {function(NodeImmediate): void=} clearImmediate +     * @property {function(number[]):number[]=} hrtime +     * @property {NextTick=} nextTick +     * @property {Performance=} performance +     * @property {RequestAnimationFrame=} requestAnimationFrame +     * @property {boolean=} queueMicrotask +     * @property {function(number): void=} cancelAnimationFrame +     * @property {RequestIdleCallback=} requestIdleCallback +     * @property {function(number): void=} cancelIdleCallback +     */ + +    /** @type {Timers} */ +    const timers = { +        setTimeout: _global.setTimeout, +        clearTimeout: _global.clearTimeout, +        setInterval: _global.setInterval, +        clearInterval: _global.clearInterval, +        Date: _global.Date, +    }; + +    if (setImmediatePresent) { +        timers.setImmediate = _global.setImmediate; +        timers.clearImmediate = _global.clearImmediate; +    } + +    if (hrtimePresent) { +        timers.hrtime = _global.process.hrtime; +    } + +    if (nextTickPresent) { +        timers.nextTick = _global.process.nextTick; +    } + +    if (performancePresent) { +        timers.performance = _global.performance; +    } + +    if (requestAnimationFramePresent) { +        timers.requestAnimationFrame = _global.requestAnimationFrame; +    } + +    if (queueMicrotaskPresent) { +        timers.queueMicrotask = true; +    } + +    if (cancelAnimationFramePresent) { +        timers.cancelAnimationFrame = _global.cancelAnimationFrame; +    } + +    if (requestIdleCallbackPresent) { +        timers.requestIdleCallback = _global.requestIdleCallback; +    } + +    if (cancelIdleCallbackPresent) { +        timers.cancelIdleCallback = _global.cancelIdleCallback; +    } + +    const originalSetTimeout = _global.setImmediate || _global.setTimeout; + +    /** +     * @param {Date|number} [start] the system time - non-integer values are floored +     * @param {number} [loopLimit] maximum number of timers that will be run when calling runAll() +     * @returns {Clock} +     */ +    function createClock(start, loopLimit) { +        // eslint-disable-next-line no-param-reassign +        start = Math.floor(getEpoch(start)); +        // eslint-disable-next-line no-param-reassign +        loopLimit = loopLimit || 1000; +        let nanos = 0; +        const adjustedSystemTime = [0, 0]; // [millis, nanoremainder] + +        if (NativeDate === undefined) { +            throw new Error( +                "The global scope doesn't have a `Date` object" + +                    " (see https://github.com/sinonjs/sinon/issues/1852#issuecomment-419622780)" +            ); +        } + +        const clock = { +            now: start, +            Date: createDate(), +            loopLimit: loopLimit, +        }; + +        clock.Date.clock = clock; + +        //eslint-disable-next-line jsdoc/require-jsdoc +        function getTimeToNextFrame() { +            return 16 - ((clock.now - start) % 16); +        } + +        //eslint-disable-next-line jsdoc/require-jsdoc +        function hrtime(prev) { +            const millisSinceStart = clock.now - adjustedSystemTime[0] - start; +            const secsSinceStart = Math.floor(millisSinceStart / 1000); +            const remainderInNanos = +                (millisSinceStart - secsSinceStart * 1e3) * 1e6 + +                nanos - +                adjustedSystemTime[1]; + +            if (Array.isArray(prev)) { +                if (prev[1] > 1e9) { +                    throw new TypeError( +                        "Number of nanoseconds can't exceed a billion" +                    ); +                } + +                const oldSecs = prev[0]; +                let nanoDiff = remainderInNanos - prev[1]; +                let secDiff = secsSinceStart - oldSecs; + +                if (nanoDiff < 0) { +                    nanoDiff += 1e9; +                    secDiff -= 1; +                } + +                return [secDiff, nanoDiff]; +            } +            return [secsSinceStart, remainderInNanos]; +        } + +        if (hrtimeBigintPresent) { +            hrtime.bigint = function () { +                const parts = hrtime(); +                return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]); // eslint-disable-line +            }; +        } + +        clock.requestIdleCallback = function requestIdleCallback( +            func, +            timeout +        ) { +            let timeToNextIdlePeriod = 0; + +            if (clock.countTimers() > 0) { +                timeToNextIdlePeriod = 50; // const for now +            } + +            const result = addTimer(clock, { +                func: func, +                args: Array.prototype.slice.call(arguments, 2), +                delay: +                    typeof timeout === "undefined" +                        ? timeToNextIdlePeriod +                        : Math.min(timeout, timeToNextIdlePeriod), +                idleCallback: true, +            }); + +            return Number(result); +        }; + +        clock.cancelIdleCallback = function cancelIdleCallback(timerId) { +            return clearTimer(clock, timerId, "IdleCallback"); +        }; + +        clock.setTimeout = function setTimeout(func, timeout) { +            return addTimer(clock, { +                func: func, +                args: Array.prototype.slice.call(arguments, 2), +                delay: timeout, +            }); +        }; +        if (typeof _global.Promise !== "undefined" && utilPromisify) { +            clock.setTimeout[ +                utilPromisify.custom +            ] = function promisifiedSetTimeout(timeout, arg) { +                return new _global.Promise(function setTimeoutExecutor( +                    resolve +                ) { +                    addTimer(clock, { +                        func: resolve, +                        args: [arg], +                        delay: timeout, +                    }); +                }); +            }; +        } + +        clock.clearTimeout = function clearTimeout(timerId) { +            return clearTimer(clock, timerId, "Timeout"); +        }; + +        clock.nextTick = function nextTick(func) { +            return enqueueJob(clock, { +                func: func, +                args: Array.prototype.slice.call(arguments, 1), +                error: isNearInfiniteLimit ? new Error() : null, +            }); +        }; + +        clock.queueMicrotask = function queueMicrotask(func) { +            return clock.nextTick(func); // explicitly drop additional arguments +        }; + +        clock.setInterval = function setInterval(func, timeout) { +            // eslint-disable-next-line no-param-reassign +            timeout = parseInt(timeout, 10); +            return addTimer(clock, { +                func: func, +                args: Array.prototype.slice.call(arguments, 2), +                delay: timeout, +                interval: timeout, +            }); +        }; + +        clock.clearInterval = function clearInterval(timerId) { +            return clearTimer(clock, timerId, "Interval"); +        }; + +        if (setImmediatePresent) { +            clock.setImmediate = function setImmediate(func) { +                return addTimer(clock, { +                    func: func, +                    args: Array.prototype.slice.call(arguments, 1), +                    immediate: true, +                }); +            }; + +            if (typeof _global.Promise !== "undefined" && utilPromisify) { +                clock.setImmediate[ +                    utilPromisify.custom +                ] = function promisifiedSetImmediate(arg) { +                    return new _global.Promise(function setImmediateExecutor( +                        resolve +                    ) { +                        addTimer(clock, { +                            func: resolve, +                            args: [arg], +                            immediate: true, +                        }); +                    }); +                }; +            } + +            clock.clearImmediate = function clearImmediate(timerId) { +                return clearTimer(clock, timerId, "Immediate"); +            }; +        } + +        clock.countTimers = function countTimers() { +            return ( +                Object.keys(clock.timers || {}).length + +                (clock.jobs || []).length +            ); +        }; + +        clock.requestAnimationFrame = function requestAnimationFrame(func) { +            const result = addTimer(clock, { +                func: func, +                delay: getTimeToNextFrame(), +                args: [clock.now + getTimeToNextFrame()], +                animation: true, +            }); + +            return Number(result); +        }; + +        clock.cancelAnimationFrame = function cancelAnimationFrame(timerId) { +            return clearTimer(clock, timerId, "AnimationFrame"); +        }; + +        clock.runMicrotasks = function runMicrotasks() { +            runJobs(clock); +        }; + +        /** +         * @param {number|string} tickValue milliseconds or a string parseable by parseTime +         * @param {boolean} isAsync +         * @param {Function} resolve +         * @param {Function} reject +         * @returns {number|undefined} will return the new `now` value or nothing for async +         */ +        function doTick(tickValue, isAsync, resolve, reject) { +            const msFloat = +                typeof tickValue === "number" +                    ? tickValue +                    : parseTime(tickValue); +            const ms = Math.floor(msFloat); +            const remainder = nanoRemainder(msFloat); +            let nanosTotal = nanos + remainder; +            let tickTo = clock.now + ms; + +            if (msFloat < 0) { +                throw new TypeError("Negative ticks are not supported"); +            } + +            // adjust for positive overflow +            if (nanosTotal >= 1e6) { +                tickTo += 1; +                nanosTotal -= 1e6; +            } + +            nanos = nanosTotal; +            let tickFrom = clock.now; +            let previous = clock.now; +            // ESLint fails to detect this correctly +            /* eslint-disable prefer-const */ +            let timer, +                firstException, +                oldNow, +                nextPromiseTick, +                compensationCheck, +                postTimerCall; +            /* eslint-enable prefer-const */ + +            clock.duringTick = true; + +            // perform microtasks +            oldNow = clock.now; +            runJobs(clock); +            if (oldNow !== clock.now) { +                // compensate for any setSystemTime() call during microtask callback +                tickFrom += clock.now - oldNow; +                tickTo += clock.now - oldNow; +            } + +            //eslint-disable-next-line jsdoc/require-jsdoc +            function doTickInner() { +                // perform each timer in the requested range +                timer = firstTimerInRange(clock, tickFrom, tickTo); +                // eslint-disable-next-line no-unmodified-loop-condition +                while (timer && tickFrom <= tickTo) { +                    if (clock.timers[timer.id]) { +                        tickFrom = timer.callAt; +                        clock.now = timer.callAt; +                        oldNow = clock.now; +                        try { +                            runJobs(clock); +                            callTimer(clock, timer); +                        } catch (e) { +                            firstException = firstException || e; +                        } + +                        if (isAsync) { +                            // finish up after native setImmediate callback to allow +                            // all native es6 promises to process their callbacks after +                            // each timer fires. +                            originalSetTimeout(nextPromiseTick); +                            return; +                        } + +                        compensationCheck(); +                    } + +                    postTimerCall(); +                } + +                // perform process.nextTick()s again +                oldNow = clock.now; +                runJobs(clock); +                if (oldNow !== clock.now) { +                    // compensate for any setSystemTime() call during process.nextTick() callback +                    tickFrom += clock.now - oldNow; +                    tickTo += clock.now - oldNow; +                } +                clock.duringTick = false; + +                // corner case: during runJobs new timers were scheduled which could be in the range [clock.now, tickTo] +                timer = firstTimerInRange(clock, tickFrom, tickTo); +                if (timer) { +                    try { +                        clock.tick(tickTo - clock.now); // do it all again - for the remainder of the requested range +                    } catch (e) { +                        firstException = firstException || e; +                    } +                } else { +                    // no timers remaining in the requested range: move the clock all the way to the end +                    clock.now = tickTo; + +                    // update nanos +                    nanos = nanosTotal; +                } +                if (firstException) { +                    throw firstException; +                } + +                if (isAsync) { +                    resolve(clock.now); +                } else { +                    return clock.now; +                } +            } + +            nextPromiseTick = +                isAsync && +                function () { +                    try { +                        compensationCheck(); +                        postTimerCall(); +                        doTickInner(); +                    } catch (e) { +                        reject(e); +                    } +                }; + +            compensationCheck = function () { +                // compensate for any setSystemTime() call during timer callback +                if (oldNow !== clock.now) { +                    tickFrom += clock.now - oldNow; +                    tickTo += clock.now - oldNow; +                    previous += clock.now - oldNow; +                } +            }; + +            postTimerCall = function () { +                timer = firstTimerInRange(clock, previous, tickTo); +                previous = tickFrom; +            }; + +            return doTickInner(); +        } + +        /** +         * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15" +         * @returns {number} will return the new `now` value +         */ +        clock.tick = function tick(tickValue) { +            return doTick(tickValue, false); +        }; + +        if (typeof _global.Promise !== "undefined") { +            /** +             * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15" +             * @returns {Promise} +             */ +            clock.tickAsync = function tickAsync(tickValue) { +                return new _global.Promise(function (resolve, reject) { +                    originalSetTimeout(function () { +                        try { +                            doTick(tickValue, true, resolve, reject); +                        } catch (e) { +                            reject(e); +                        } +                    }); +                }); +            }; +        } + +        clock.next = function next() { +            runJobs(clock); +            const timer = firstTimer(clock); +            if (!timer) { +                return clock.now; +            } + +            clock.duringTick = true; +            try { +                clock.now = timer.callAt; +                callTimer(clock, timer); +                runJobs(clock); +                return clock.now; +            } finally { +                clock.duringTick = false; +            } +        }; + +        if (typeof _global.Promise !== "undefined") { +            clock.nextAsync = function nextAsync() { +                return new _global.Promise(function (resolve, reject) { +                    originalSetTimeout(function () { +                        try { +                            const timer = firstTimer(clock); +                            if (!timer) { +                                resolve(clock.now); +                                return; +                            } + +                            let err; +                            clock.duringTick = true; +                            clock.now = timer.callAt; +                            try { +                                callTimer(clock, timer); +                            } catch (e) { +                                err = e; +                            } +                            clock.duringTick = false; + +                            originalSetTimeout(function () { +                                if (err) { +                                    reject(err); +                                } else { +                                    resolve(clock.now); +                                } +                            }); +                        } catch (e) { +                            reject(e); +                        } +                    }); +                }); +            }; +        } + +        clock.runAll = function runAll() { +            let numTimers, i; +            runJobs(clock); +            for (i = 0; i < clock.loopLimit; i++) { +                if (!clock.timers) { +                    resetIsNearInfiniteLimit(); +                    return clock.now; +                } + +                numTimers = Object.keys(clock.timers).length; +                if (numTimers === 0) { +                    resetIsNearInfiniteLimit(); +                    return clock.now; +                } + +                clock.next(); +                checkIsNearInfiniteLimit(clock, i); +            } + +            const excessJob = firstTimer(clock); +            throw getInfiniteLoopError(clock, excessJob); +        }; + +        clock.runToFrame = function runToFrame() { +            return clock.tick(getTimeToNextFrame()); +        }; + +        if (typeof _global.Promise !== "undefined") { +            clock.runAllAsync = function runAllAsync() { +                return new _global.Promise(function (resolve, reject) { +                    let i = 0; +                    /** +                     * +                     */ +                    function doRun() { +                        originalSetTimeout(function () { +                            try { +                                let numTimers; +                                if (i < clock.loopLimit) { +                                    if (!clock.timers) { +                                        resetIsNearInfiniteLimit(); +                                        resolve(clock.now); +                                        return; +                                    } + +                                    numTimers = Object.keys(clock.timers) +                                        .length; +                                    if (numTimers === 0) { +                                        resetIsNearInfiniteLimit(); +                                        resolve(clock.now); +                                        return; +                                    } + +                                    clock.next(); + +                                    i++; + +                                    doRun(); +                                    checkIsNearInfiniteLimit(clock, i); +                                    return; +                                } + +                                const excessJob = firstTimer(clock); +                                reject(getInfiniteLoopError(clock, excessJob)); +                            } catch (e) { +                                reject(e); +                            } +                        }); +                    } +                    doRun(); +                }); +            }; +        } + +        clock.runToLast = function runToLast() { +            const timer = lastTimer(clock); +            if (!timer) { +                runJobs(clock); +                return clock.now; +            } + +            return clock.tick(timer.callAt - clock.now); +        }; + +        if (typeof _global.Promise !== "undefined") { +            clock.runToLastAsync = function runToLastAsync() { +                return new _global.Promise(function (resolve, reject) { +                    originalSetTimeout(function () { +                        try { +                            const timer = lastTimer(clock); +                            if (!timer) { +                                resolve(clock.now); +                            } + +                            resolve(clock.tickAsync(timer.callAt)); +                        } catch (e) { +                            reject(e); +                        } +                    }); +                }); +            }; +        } + +        clock.reset = function reset() { +            nanos = 0; +            clock.timers = {}; +            clock.jobs = []; +            clock.now = start; +        }; + +        clock.setSystemTime = function setSystemTime(systemTime) { +            // determine time difference +            const newNow = getEpoch(systemTime); +            const difference = newNow - clock.now; +            let id, timer; + +            adjustedSystemTime[0] = adjustedSystemTime[0] + difference; +            adjustedSystemTime[1] = adjustedSystemTime[1] + nanos; +            // update 'system clock' +            clock.now = newNow; +            nanos = 0; + +            // update timers and intervals to keep them stable +            for (id in clock.timers) { +                if (clock.timers.hasOwnProperty(id)) { +                    timer = clock.timers[id]; +                    timer.createdAt += difference; +                    timer.callAt += difference; +                } +            } +        }; + +        if (performancePresent) { +            clock.performance = Object.create(null); + +            if (hasPerformancePrototype) { +                const proto = _global.Performance.prototype; + +                Object.getOwnPropertyNames(proto).forEach(function (name) { +                    if (name.indexOf("getEntries") === 0) { +                        // match expected return type for getEntries functions +                        clock.performance[name] = NOOP_ARRAY; +                    } else { +                        clock.performance[name] = NOOP; +                    } +                }); +            } + +            clock.performance.now = function FakeTimersNow() { +                const hrt = hrtime(); +                const millis = hrt[0] * 1000 + hrt[1] / 1e6; +                return millis; +            }; +        } + +        if (hrtimePresent) { +            clock.hrtime = hrtime; +        } + +        return clock; +    } + +    /* eslint-disable complexity */ + +    /** +     * @param {Config=} [config] Optional config +     * @returns {Clock} +     */ +    function install(config) { +        if ( +            arguments.length > 1 || +            config instanceof Date || +            Array.isArray(config) || +            typeof config === "number" +        ) { +            throw new TypeError( +                `FakeTimers.install called with ${String( +                    config +                )} install requires an object parameter` +            ); +        } + +        // eslint-disable-next-line no-param-reassign +        config = typeof config !== "undefined" ? config : {}; +        config.shouldAdvanceTime = config.shouldAdvanceTime || false; +        config.advanceTimeDelta = config.advanceTimeDelta || 20; +        config.shouldClearNativeTimers = +            config.shouldClearNativeTimers || false; + +        if (config.target) { +            throw new TypeError( +                "config.target is no longer supported. Use `withGlobal(target)` instead." +            ); +        } + +        let i, l; +        const clock = createClock(config.now, config.loopLimit); +        clock.shouldClearNativeTimers = config.shouldClearNativeTimers; + +        clock.uninstall = function () { +            return uninstall(clock, config); +        }; + +        clock.methods = config.toFake || []; + +        if (clock.methods.length === 0) { +            // do not fake nextTick by default - GitHub#126 +            clock.methods = Object.keys(timers).filter(function (key) { +                return key !== "nextTick" && key !== "queueMicrotask"; +            }); +        } + +        if (config.shouldAdvanceTime === true) { +            const intervalTick = doIntervalTick.bind( +                null, +                clock, +                config.advanceTimeDelta +            ); +            const intervalId = _global.setInterval( +                intervalTick, +                config.advanceTimeDelta +            ); +            clock.attachedInterval = intervalId; +        } + +        for (i = 0, l = clock.methods.length; i < l; i++) { +            const nameOfMethodToReplace = clock.methods[i]; +            if (nameOfMethodToReplace === "hrtime") { +                if ( +                    _global.process && +                    typeof _global.process.hrtime === "function" +                ) { +                    hijackMethod(_global.process, nameOfMethodToReplace, clock); +                } +            } else if (nameOfMethodToReplace === "nextTick") { +                if ( +                    _global.process && +                    typeof _global.process.nextTick === "function" +                ) { +                    hijackMethod(_global.process, nameOfMethodToReplace, clock); +                } +            } else { +                hijackMethod(_global, nameOfMethodToReplace, clock); +            } +        } + +        return clock; +    } + +    /* eslint-enable complexity */ + +    return { +        timers: timers, +        createClock: createClock, +        install: install, +        withGlobal: withGlobal, +    }; +} + +/** + * @typedef {object} FakeTimers + * @property {Timers} timers + * @property {createClock} createClock + * @property {Function} install + * @property {withGlobal} withGlobal + */ + +/* eslint-enable complexity */ + +/** @type {FakeTimers} */ +const defaultImplementation = withGlobal(globalObject); + +exports.timers = defaultImplementation.timers; +exports.createClock = defaultImplementation.createClock; +exports.install = defaultImplementation.install; +exports.withGlobal = withGlobal;  | 
