UNPKG

traverson

Version:

Hypermedia API/HATEOAS client for Node.js and the browser

1,671 lines (1,427 loc) 4.32 MB
// modules are defined as an array // [ module function, map of requireuires ] // // map of requireuires is short require name -> numeric require // // anything defined in a previous bundle is accessed via the // orig method which is the requireuire for previous bundles (function outer (modules, cache, entry) { // Save the require from previous bundle to this closure if any var previousRequire = typeof require == "function" && require; function findProxyquireifyName() { var deps = Object.keys(modules) .map(function (k) { return modules[k][1]; }); for (var i = 0; i < deps.length; i++) { var pq = deps[i]['proxyquireify']; if (pq) return pq; } } var proxyquireifyName = findProxyquireifyName(); function newRequire(name, jumped){ // Find the proxyquireify module, if present var pqify = (proxyquireifyName != null) && cache[proxyquireifyName]; // Proxyquireify provides a separate cache that is used when inside // a proxyquire call, and is set to null outside a proxyquire call. // This allows the regular caching semantics to work correctly both // inside and outside proxyquire calls while keeping the cached // modules isolated. // When switching from one proxyquire call to another, it clears // the cache to prevent contamination between different sets // of stubs. var currentCache = (pqify && pqify.exports._cache) || cache; if(!currentCache[name]) { if(!modules[name]) { // if we cannot find the the module within our internal map or // cache jump to the current global require ie. the last bundle // that was added to the page. var currentRequire = typeof require == "function" && require; if (!jumped && currentRequire) return currentRequire(name, true); // If there are other bundles on this page the require from the // previous one is saved to 'previousRequire'. Repeat this as // many times as there are bundles until the module is found or // we exhaust the require chain. if (previousRequire) return previousRequire(name, true); var err = new Error('Cannot find module \'' + name + '\''); err.code = 'MODULE_NOT_FOUND'; throw err; } var m = currentCache[name] = {exports:{}}; // The normal browserify require function var req = function(x){ var id = modules[name][1][x]; return newRequire(id ? id : x); }; // The require function substituted for proxyquireify var moduleRequire = function(x){ var pqify = (proxyquireifyName != null) && cache[proxyquireifyName]; // Only try to use the proxyquireify version if it has been `require`d if (pqify && pqify.exports._proxy) { return pqify.exports._proxy(req, x); } else { return req(x); } }; modules[name][0].call(m.exports,moduleRequire,m,m.exports,outer,modules,currentCache,entry); } return currentCache[name].exports; } for(var i=0;i<entry.length;i++) newRequire(entry[i]); // Override the current require with this new one return newRequire; }) ({1:[function(require,module,exports){ 'use strict'; // TODO Replace by a proper lightweight logging module, suited for the browser var enabled = false; function Logger(id) { if (id == null) { id = ''; } this.id = id; } Logger.prototype.enable = function() { this.enabled = true; }; Logger.prototype.debug = function(message) { if (enabled) { console.log(this.id + '/debug: ' + message); } }; Logger.prototype.info = function(message) { if (enabled) { console.log(this.id + '/info: ' + message); } }; Logger.prototype.warn = function(message) { if (enabled) { console.log(this.id + '/warn: ' + message); } }; Logger.prototype.error = function(message) { if (enabled) { console.log(this.id + '/error: ' + message); } }; function minilog(id) { return new Logger(id); } minilog.enable = function() { enabled = true; }; module.exports = minilog; },{}],2:[function(require,module,exports){ 'use strict'; module.exports = { isArray: function(o) { if (o == null) { return false; } return Object.prototype.toString.call(o) === '[object Array]'; } }; },{}],3:[function(require,module,exports){ 'use strict'; /* * Copied from underscore.string module. Just the functions we need, to reduce * the browserified size. */ var _s = { startsWith: function(str, starts) { if (starts === '') return true; if (str == null || starts == null) return false; str = String(str); starts = String(starts); return str.length >= starts.length && str.slice(0, starts.length) === starts; }, endsWith: function(str, ends){ if (ends === '') return true; if (str == null || ends == null) return false; str = String(str); ends = String(ends); return str.length >= ends.length && str.slice(str.length - ends.length) === ends; }, splice: function(str, i, howmany, substr){ var arr = _s.chars(str); arr.splice(~~i, ~~howmany, substr); return arr.join(''); }, contains: function(str, needle){ if (needle === '') return true; if (str == null) return false; return String(str).indexOf(needle) !== -1; }, chars: function(str) { if (str == null) return []; return String(str).split(''); } }; module.exports = _s; },{}],4:[function(require,module,exports){ 'use strict'; var minilog = require('minilog') , errorModule = require('./errors') , errors = errorModule.errors , createError = errorModule.createError , log = minilog('traverson'); exports.abortTraversal = function abortTraversal() { log.debug('aborting link traversal'); this.aborted = true; if (this.currentRequest) { log.debug('request in progress. trying to abort it, too.'); this.currentRequest.abort(); } }; exports.registerAbortListener = function registerAbortListener(t, callback) { if (t.currentRequest) { t.currentRequest.on('abort', function() { exports.callCallbackOnAbort(t); }); } }; exports.callCallbackOnAbort = function callCallbackOnAbort(t) { log.debug('link traversal aborted'); if (!t.callbackHasBeenCalledAfterAbort) { t.callbackHasBeenCalledAfterAbort = true; t.callback(exports.abortError(), t); } }; exports.abortError = function abortError() { var error = createError('Link traversal process has been aborted.', errors.TraversalAbortedError); error.aborted = true; return error; }; },{"./errors":5,"minilog":1}],5:[function(require,module,exports){ 'use strict'; module.exports = { errors: { HTTPError: 'HTTPError', InvalidArgumentError: 'InvalidArgumentError', InvalidStateError: 'InvalidStateError', JSONError: 'JSONError', JSONPathError: 'JSONPathError', LinkError: 'LinkError', TraversalAbortedError: 'TraversalAbortedError', UnsupportedMediaType: 'UnsupportedMediaTypeError', }, createError: function(message, name, data) { var error = new Error(message); error.name = name; if (data) { error.data = data; } return error; }, }; },{}],6:[function(require,module,exports){ (function (process){(function (){ 'use strict'; var minilog = require('minilog') , log = minilog('traverson') , abortTraversal = require('./abort_traversal') , detectContentType = require('./transforms/detect_content_type') , errorModule = require('./errors') , errors = errorModule.errors , createError = errorModule.createError , getOptionsForStep = require('./transforms/get_options_for_step'); var nextTickAvailable = process && Object.hasOwnProperty.call(process, 'nextTick'); /** * Executes a HTTP GET request during the link traversal process. */ // This method is currently used for all intermediate GET requests during the // link traversal process. Coincidentally, it is also used for the final request // in a link traversal should this happen to be a GET request. Otherwise (POST/ // PUT/PATCH/DELETE), Traverson uses exectueHttpRequest. exports.fetchResource = function fetchResource(t, callback) { log.debug('fetching resource for next step'); if (t.step.url) { log.debug('fetching resource from', t.step.url); return executeHttpGet(t, callback); } else if (t.step.doc) { // The step already has an attached result document, so all is fine and we // can call the callback immediately log.debug('resource for next step has already been fetched, using ' + 'embedded'); if (nextTickAvailable) { return process.nextTick(function() { callback(null, t); }); } return callback(null, t); } else { var error = createError('Can not process step.', errors.InvalidStateError); error.step = t.step; if (nextTickAvailable) { return process.nextTick(function() { callback(error, t); }); } return callback(error, t); } }; function executeHttpGet(t, callback) { var options = getOptionsForStep(t); log.debug('HTTP GET request to', t.step.url); log.debug('options', options); t.mostRecentHttpMethodName = 'GET'; t.currentRequest = t.requestModuleInstance.get(t.step.url, options, function(err, response, body) { log.debug('HTTP GET request to', t.step.url, 'returned'); t.currentRequest = null; // workaround for cases where response body is empty but body comes in as // the third argument if (body && !response.body) { response.body = body; } t.step.response = response; if (err) { return callback(err, t); } log.debug('request to', t.step.url, 'finished without error (', response.statusCode, ')'); if (!detectContentType(t, callback)) return; return callback(null, t); }); abortTraversal.registerAbortListener(t, callback); } /** * Executes an arbitrary HTTP request. */ // This method is currently used for POST/PUT/PATCH/DELETE at the end of a link // traversal process. If the link traversal process requires a GET as the last // request, Traverson uses exectueHttpGet. exports.executeHttpRequest = function(t, request, method, methodName, callback) { var requestOptions = getOptionsForStep(t); if (t.body !== null && typeof t.body !== 'undefined') { requestOptions.body = (t.rawPayload || requestOptions.jsonReplacer) ? t.body : JSON.stringify(t.body); } log.debug('HTTP', methodName, 'request to', t.step.url); log.debug('options', requestOptions); t.mostRecentHttpMethodName = methodName; t.currentRequest = method.call(request, t.step.url, requestOptions, function(err, response, body) { log.debug('HTTP', methodName, 'request to', t.step.url, 'returned'); t.currentRequest = null; // workaround for cases where response body is empty but body comes in as // the third argument if (body && !response.body) { response.body = body; } t.step.response = response; if (err) { return callback(err); } return callback(null, response); }); abortTraversal.registerAbortListener(t, callback); }; }).call(this)}).call(this,require('_process')) },{"./abort_traversal":4,"./errors":5,"./transforms/detect_content_type":15,"./transforms/get_options_for_step":17,"_process":150,"minilog":1}],7:[function(require,module,exports){ 'use strict'; module.exports = function isContinuation(t) { return t.continuation && t.step && t.step.response; }; },{}],8:[function(require,module,exports){ 'use strict'; var minilog = require('minilog') , _s = require('underscore.string'); var jsonpath; try { jsonpath = require('jsonpath-plus'); } catch (e) { jsonpath = false; console.warn('Could not require jsonpath-plus, JSONPath support is not ' + 'available.'); } var errorModule = require('./errors') , errors = errorModule.errors , createError = errorModule.createError , parseLinkHeaderValue = require('./parse_link_header_value'); function JsonAdapter(log) { this.log = log; } JsonAdapter.mediaType = 'application/json'; JsonAdapter.prototype.findNextStep = function(t, link) { validateLinkObject(link); var doc = t.lastStep.doc; this.log.debug('resolving link', link); switch (link.type) { case 'link-rel': return this._handleLinkRel(doc, link); case 'header': return this._handleHeader(t.lastStep.response, link); case 'link-header': return this._handleLinkHeader(t.lastStep.response, link); default: throw createError('Link objects with type ' + link.type + ' are not ' + 'supported by this adapter.', errors.InvalidArgumentError, link); } }; JsonAdapter.prototype._handleLinkRel = function(doc, link) { var linkRel = link.value; this.log.debug('looking for link-rel', linkRel, 'in doc', doc); var url; if (this._testJSONPath(linkRel)) { return { url: this._resolveJSONPath(doc, linkRel) }; } else if (doc[linkRel]) { return { url : doc[linkRel] }; } else { throw createError('Could not find property ' + linkRel + ' in document.', errors.LinkError, doc); } }; function validateLinkObject(link) { if (typeof link === 'undefined' || link === null) { throw createError('Link object is null or undefined.', errors.InvalidArgumentError); } if (typeof link !== 'object') { throw createError('Links must be objects, not ' + typeof link + '.', errors.InvalidArgumentError, link); } if (!link.type) { throw createError('Link objects has no type attribute.', errors.InvalidArgumentError, link); } } JsonAdapter.prototype._testJSONPath = function(link) { return _s.startsWith(link, '$.') || _s.startsWith(link, '$['); }; JsonAdapter.prototype._resolveJSONPath = function(doc, link) { if (!jsonpath) { throw createError('JSONPath support is not available.'); } var matches = jsonpath({ json: doc, path: link, }); if (matches.length === 1) { var url = matches[0]; if (!url) { throw createError('JSONPath expression ' + link + ' was resolved but the result was null, undefined or an empty' + ' string in document:\n' + JSON.stringify(doc), errors.JSONPathError, doc); } if (typeof url !== 'string') { throw createError('JSONPath expression ' + link + ' was resolved but the result is not a property of type string. ' + 'Instead it has type "' + (typeof url) + '" in document:\n' + JSON.stringify(doc), errors.JSONPathError, doc); } return url; } else if (matches.length > 1) { // ambigious match throw createError('JSONPath expression ' + link + ' returned more than one match in document:\n' + JSON.stringify(doc), errors.JSONPathError, doc); } else { // no match at all throw createError('JSONPath expression ' + link + ' returned no match in document:\n' + JSON.stringify(doc), errors.JSONPathError, doc); } }; JsonAdapter.prototype._handleHeader = function(httpResponse, link) { switch (link.value) { case 'location': var locationHeader = httpResponse.headers.location; if (!locationHeader) { throw createError('Following the location header but there was no ' + 'location header in the last response.', errors.LinkError, httpResponse.headers); } return { url : locationHeader }; default: throw createError('Link objects with type header and value ' + link.value + ' are not supported by this adapter.', errors.InvalidArgumentError, link); } }; JsonAdapter.prototype._handleLinkHeader = function(httpResponse, link) { if (!httpResponse.headers.link) throw createError('There was no link header in the last response.', errors.InvalidArgumentError, link); var links = parseLinkHeaderValue(httpResponse.headers.link); if (links[link.value]) { return { url : links[link.value].url}; } else { throw createError('Link with relation ' + link.value + ' not found in link header.', errors.InvalidArgumentError, link); } }; module.exports = JsonAdapter; },{"./errors":5,"./parse_link_header_value":13,"jsonpath-plus":128,"minilog":1,"underscore.string":3}],9:[function(require,module,exports){ 'use strict'; var mediaTypes = require('./media_types'); var registry = {}; exports.register = function register(contentType, constructor) { registry[contentType] = constructor; }; exports.get = function get(contentType) { return registry[contentType]; }; exports.register(mediaTypes.CONTENT_NEGOTIATION, require('./negotiation_adapter')); exports.register(mediaTypes.JSON, require('./json_adapter')); },{"./json_adapter":8,"./media_types":10,"./negotiation_adapter":12}],10:[function(require,module,exports){ 'use strict'; var JsonAdapter = require('./json_adapter'); module.exports = { CONTENT_NEGOTIATION: 'content-negotiation', JSON: JsonAdapter.mediaType, JSON_HAL: 'application/hal+json', }; },{"./json_adapter":8}],11:[function(require,module,exports){ 'use strict'; // TODO Maybe replace with https://github.com/Raynos/xtend // check browser build size, though. function mergeRecursive(obj1, obj2) { if (!obj1 && obj2) { obj1 = {}; } for (var key in obj2) { if (!obj2.hasOwnProperty(key)) { continue; } merge(obj1, obj2, key); } return obj1; } function merge(obj1, obj2, key) { if (typeof obj2[key] === 'object') { // if it is an object (that is, a non-leave in the tree), // and it is not present in obj1 if (!obj1[key] || typeof obj1[key] !== 'object') { // ... we create an empty object in obj1 obj1[key] = {}; } // and we recurse deeper into the structure mergeRecursive(obj1[key], obj2[key]); } else { // if it is primitive (string, number, boolean) or a function, we overwrite/ // add it to obj1 obj1[key] = obj2[key]; } } module.exports = mergeRecursive; },{}],12:[function(require,module,exports){ 'use strict'; var errorModule = require('./errors') , errors = errorModule.errors , createError = errorModule.createError; function NegotiationAdapter(log) {} NegotiationAdapter.prototype.findNextStep = function(doc, link) { throw createError('Content negotiation did not happen', errors.InvalidStateError); }; module.exports = NegotiationAdapter; },{"./errors":5}],13:[function(require,module,exports){ var mergeRecursive = require('./merge_recursive'); module.exports = function parseLinkHeaderValue(linkHeader) { if (!linkHeader) { return null; } return linkHeader .split(/,\s*</) .map(parseLink) .filter(hasRel) .reduce(intoRels, {}); }; function parseLink(link) { try { var parts = link.split(';'); var linkUrl = parts.shift().replace(/[<>]/g, ''); var info = parts.reduce(createObjects, {}); info.url = linkUrl; return info; } catch (e) { return null; } } function createObjects(acc, p) { // rel="next" => 1: rel 2: next var m = p.match(/\s*(.+)\s*=\s*"?([^"]+)"?/); if (m) acc[m[1]] = m[2]; return acc; } function hasRel(linkHeaderValuePart) { return linkHeaderValuePart && linkHeaderValuePart.rel; } function intoRels(acc, linkHeaderValuePart) { function splitRel (rel) { acc[rel] = mergeRecursive({ rel: rel }, linkHeaderValuePart); } linkHeaderValuePart.rel.split(/\s+/).forEach(splitRel); return acc; } },{"./merge_recursive":11}],14:[function(require,module,exports){ (function (process){(function (){ /* jshint loopfunc: true */ 'use strict'; var minilog = require('minilog') , log = minilog('traverson'); var nextTickAvailable = process && Object.hasOwnProperty.call(process, 'nextTick'); /* * Applies async and sync transforms, one after another. */ function applyTransforms(transforms, t, callback) { log.debug('applying', transforms.length, 'transforms'); for (var i = 0; i < transforms.length; i++) { var transform = transforms[i]; log.debug('next transform', transform); if (transform.isAsync) { // asynchronous case return transform(t, function(t) { // this is only called when the async transform was successful, // otherwise t.callback has already been called with an error. applyTransforms(transforms.slice(i + 1), t, callback); }); } else { // synchronous case var result = transform(t); if (!result) { log.debug('transform has failed or was a final transform'); // stop processing t.callback has already been called return; } } } log.debug('all transformations done, starting next step'); if (nextTickAvailable) { return process.nextTick(function() { callback(t); }); } return callback(t); } module.exports = applyTransforms; }).call(this)}).call(this,require('_process')) },{"_process":150,"minilog":1}],15:[function(require,module,exports){ 'use strict'; var minilog = require('minilog') , log = minilog('traverson'); var mediaTypeRegistry = require('../media_type_registry') , errorModule = require('../errors') , errors = errorModule.errors , createError = errorModule.createError; module.exports = function detectContentType(t, callback) { if (t.contentNegotiation && t.step.response && t.step.response.headers && t.step.response.headers['content-type']) { var contentType = t.step.response.headers['content-type'].split(/[; ]/)[0]; log.debug('found content type string', contentType); var AdapterType = mediaTypeRegistry.get(contentType); if (!AdapterType) { log.error('no adapter for content type', contentType); callback(createError('Unknown content type for content ' + 'type detection: ' + contentType, errors.UnsupportedMediaType), t); return false; } // switch to new Adapter depending on Content-Type header of server t.adapter = new AdapterType(log); log.debug('switched to media type adapter', t.adapter.name || t.adapter.constructor.name); } return true; }; },{"../errors":5,"../media_type_registry":9,"minilog":1}],16:[function(require,module,exports){ (function (process){(function (){ 'use strict'; var minilog = require('minilog') , log = minilog('traverson') , abortTraversal = require('../abort_traversal') , isContinuation = require('../is_continuation') , httpRequests = require('../http_requests'); var nextTickAvailable = process && Object.hasOwnProperty.call(process, 'nextTick'); /* * Execute the next step in the traversal. In most cases that is an HTTP get to *the next URL. */ function fetchResource(t, callback) { if (isContinuation(t)) { convertContinuation(t, callback); } else { fetchViaHttp(t, callback); } } fetchResource.isAsync = true; /* * This is a continuation of an earlier traversal process. * We need to shortcut to the next step (without executing the final HTTP * request of the last traversal again. */ function convertContinuation(t, callback) { log.debug('continuing from last traversal process (walker)'); if (nextTickAvailable) { return process.nextTick(function() { // de-zalgo continuations callback(t); }); } return callback(t); } function fetchViaHttp(t, callback) { // always check for aborted before doing an HTTP request if (t.aborted) { return abortTraversal.callCallbackOnAbort(t); } httpRequests.fetchResource(t, function(err, t) { log.debug('fetchResource returned'); if (err) { if (!err.aborted) { log.debug('error while executing http request'); log.error(err); } return t.callback(err); } callback(t); }); } module.exports = fetchResource; }).call(this)}).call(this,require('_process')) },{"../abort_traversal":4,"../http_requests":6,"../is_continuation":7,"_process":150,"minilog":1}],17:[function(require,module,exports){ 'use strict'; var minilog = require('minilog') , log = minilog('traverson') , util = require('util') , mergeRecursive = require('../merge_recursive'); module.exports = function getOptionsForStep(t) { var options = t.requestOptions; if (util.isArray(t.requestOptions)) { options = t.requestOptions[t.step.index] || {}; } if (t.autoHeaders) { addAutoHeaders(t, options); } log.debug('options', options); return options; }; function addAutoHeaders(t, options) { var autoHeaderValue = // we accept a static mediaType property as well as an instance property t.adapter.constructor.mediaType || t.adapter.mediaType; // The content negotiation adapter does not (and can not) provide a value // for automatical Accept and Content-Type headers, in this case auto header // value is undefined and we skip setting auto headers. This also happens // arbitrary media type plug-ins that do not behave well and have no // mediaType property. if (autoHeaderValue) { if (!options.headers) { options.headers = createAutoHeaders(options, autoHeaderValue); } else { options.headers = mergeRecursive( createAutoHeaders(options, autoHeaderValue), options.headers ); } } } function createAutoHeaders(options, autoHeaderValue) { if (!options.form) { // default: set Accept and Content-Type header return { 'Accept': autoHeaderValue, 'Content-Type': autoHeaderValue, }; } else { // if options.form is set, we only set the Accept header, but not not the // Content-Type header. The Content-Type header is set automatically by // request/request or by browser/lib/shim/request.js. return { 'Accept': autoHeaderValue }; } } },{"../merge_recursive":11,"minilog":1,"util":2}],18:[function(require,module,exports){ "use strict"; var every = require("./prototypes/array").every; /** * @private */ function hasCallsLeft(callMap, spy) { if (callMap[spy.id] === undefined) { callMap[spy.id] = 0; } return callMap[spy.id] < spy.callCount; } /** * @private */ function checkAdjacentCalls(callMap, spy, index, spies) { var calledBeforeNext = true; if (index !== spies.length - 1) { calledBeforeNext = spy.calledBefore(spies[index + 1]); } if (hasCallsLeft(callMap, spy) && calledBeforeNext) { callMap[spy.id] += 1; return true; } return false; } /** * A Sinon proxy object (fake, spy, stub) * * @typedef {object} SinonProxy * @property {Function} calledBefore - A method that determines if this proxy was called before another one * @property {string} id - Some id * @property {number} callCount - Number of times this proxy has been called */ /** * Returns true when the spies have been called in the order they were supplied in * * @param {SinonProxy[] | SinonProxy} spies An array of proxies, or several proxies as arguments * @returns {boolean} true when spies are called in order, false otherwise */ function calledInOrder(spies) { var callMap = {}; // eslint-disable-next-line no-underscore-dangle var _spies = arguments.length > 1 ? arguments : spies; return every(_spies, checkAdjacentCalls.bind(null, callMap)); } module.exports = calledInOrder; },{"./prototypes/array":26}],19:[function(require,module,exports){ "use strict"; var functionName = require("./function-name"); /** * Returns a display name for a value from a constructor * * @param {object} value A value to examine * @returns {(string|null)} A string or null */ function className(value) { return ( (value.constructor && value.constructor.name) || // The next branch is for IE11 support only: // Because the name property is not set on the prototype // of the Function object, we finally try to grab the // name from its definition. This will never be reached // in node, so we are not able to test this properly. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name (typeof value.constructor === "function" && /* istanbul ignore next */ functionName(value.constructor)) || null ); } module.exports = className; },{"./function-name":22}],20:[function(require,module,exports){ (function (process){(function (){ /* eslint-disable no-console */ "use strict"; /** * Returns a function that will invoke the supplied function and print a * deprecation warning to the console each time it is called. * * @param {Function} func * @param {string} msg * @returns {Function} */ exports.wrap = function(func, msg) { var wrapped = function() { exports.printWarning(msg); return func.apply(this, arguments); }; if (func.prototype) { wrapped.prototype = func.prototype; } return wrapped; }; /** * Returns a string which can be supplied to `wrap()` to notify the user that a * particular part of the sinon API has been deprecated. * * @param {string} packageName * @param {string} funcName * @returns {string} */ exports.defaultMsg = function(packageName, funcName) { return ( packageName + "." + funcName + " is deprecated and will be removed from the public API in a future version of " + packageName + "." ); }; /** * Prints a warning on the console, when it exists * * @param {string} msg * @returns {undefined} */ exports.printWarning = function(msg) { /* istanbul ignore next */ if (typeof process === "object" && process.emitWarning) { // Emit Warnings in Node process.emitWarning(msg); } else if (console.info) { console.info(msg); } else { console.log(msg); } }; }).call(this)}).call(this,require('_process')) },{"_process":150}],21:[function(require,module,exports){ "use strict"; /** * Returns true when fn returns true for all members of obj. * This is an every implementation that works for all iterables * * @param {object} obj * @param {Function} fn * @returns {boolean} */ module.exports = function every(obj, fn) { var pass = true; try { // eslint-disable-next-line @sinonjs/no-prototype-methods/no-prototype-methods obj.forEach(function() { if (!fn.apply(this, arguments)) { // Throwing an error is the only way to break `forEach` throw new Error(); } }); } catch (e) { pass = false; } return pass; }; },{}],22:[function(require,module,exports){ "use strict"; /** * Returns a display name for a function * * @param {Function} func * @returns {string} */ module.exports = function functionName(func) { if (!func) { return ""; } try { return ( func.displayName || func.name || // Use function decomposition as a last resort to get function // name. Does not rely on function decomposition to work - if it // doesn't debugging will be slightly less informative // (i.e. toString will say 'spy' rather than 'myFunc'). (String(func).match(/function ([^\s(]+)/) || [])[1] ); } catch (e) { // Stringify may fail and we might get an exception, as a last-last // resort fall back to empty string. return ""; } }; },{}],23:[function(require,module,exports){ (function (global){(function (){ "use strict"; /** * A reference to the global object * * @type {object} globalObject */ var globalObject; /* istanbul ignore else */ if (typeof global !== "undefined") { // Node globalObject = global; } else if (typeof window !== "undefined") { // Browser globalObject = window; } else { // WebWorker globalObject = self; } module.exports = globalObject; }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],24:[function(require,module,exports){ "use strict"; module.exports = { global: require("./global"), calledInOrder: require("./called-in-order"), className: require("./class-name"), deprecated: require("./deprecated"), every: require("./every"), functionName: require("./function-name"), orderByFirstCall: require("./order-by-first-call"), prototypes: require("./prototypes"), typeOf: require("./type-of"), valueToString: require("./value-to-string") }; },{"./called-in-order":18,"./class-name":19,"./deprecated":20,"./every":21,"./function-name":22,"./global":23,"./order-by-first-call":25,"./prototypes":29,"./type-of":34,"./value-to-string":35}],25:[function(require,module,exports){ "use strict"; var sort = require("./prototypes/array").sort; var slice = require("./prototypes/array").slice; /** * @private */ function comparator(a, b) { // uuid, won't ever be equal var aCall = a.getCall(0); var bCall = b.getCall(0); var aId = (aCall && aCall.callId) || -1; var bId = (bCall && bCall.callId) || -1; return aId < bId ? -1 : 1; } /** * A Sinon proxy object (fake, spy, stub) * * @typedef {object} SinonProxy * @property {Function} getCall - A method that can return the first call */ /** * Sorts an array of SinonProxy instances (fake, spy, stub) by their first call * * @param {SinonProxy[] | SinonProxy} spies * @returns {SinonProxy[]} */ function orderByFirstCall(spies) { return sort(slice(spies), comparator); } module.exports = orderByFirstCall; },{"./prototypes/array":26}],26:[function(require,module,exports){ "use strict"; var copyPrototype = require("./copy-prototype"); module.exports = copyPrototype(Array.prototype); },{"./copy-prototype":27}],27:[function(require,module,exports){ "use strict"; var call = Function.call; module.exports = function copyPrototypeMethods(prototype) { // eslint-disable-next-line @sinonjs/no-prototype-methods/no-prototype-methods return Object.getOwnPropertyNames(prototype).reduce(function(result, name) { // ignore size because it throws from Map if ( name !== "size" && name !== "caller" && name !== "callee" && name !== "arguments" && typeof prototype[name] === "function" ) { result[name] = call.bind(prototype[name]); } return result; }, Object.create(null)); }; },{}],28:[function(require,module,exports){ "use strict"; var copyPrototype = require("./copy-prototype"); module.exports = copyPrototype(Function.prototype); },{"./copy-prototype":27}],29:[function(require,module,exports){ "use strict"; module.exports = { array: require("./array"), function: require("./function"), map: require("./map"), object: require("./object"), set: require("./set"), string: require("./string") }; },{"./array":26,"./function":28,"./map":30,"./object":31,"./set":32,"./string":33}],30:[function(require,module,exports){ "use strict"; var copyPrototype = require("./copy-prototype"); module.exports = copyPrototype(Map.prototype); },{"./copy-prototype":27}],31:[function(require,module,exports){ "use strict"; var copyPrototype = require("./copy-prototype"); module.exports = copyPrototype(Object.prototype); },{"./copy-prototype":27}],32:[function(require,module,exports){ "use strict"; var copyPrototype = require("./copy-prototype"); module.exports = copyPrototype(Set.prototype); },{"./copy-prototype":27}],33:[function(require,module,exports){ "use strict"; var copyPrototype = require("./copy-prototype"); module.exports = copyPrototype(String.prototype); },{"./copy-prototype":27}],34:[function(require,module,exports){ "use strict"; var type = require("type-detect"); /** * Returns the lower-case result of running type from type-detect on the value * * @param {*} value * @returns {string} */ module.exports = function typeOf(value) { return type(value).toLowerCase(); }; },{"type-detect":195}],35:[function(require,module,exports){ "use strict"; /** * Returns a string representation of the value * * @param {*} value * @returns {string} */ function valueToString(value) { if (value && value.toString) { // eslint-disable-next-line @sinonjs/no-prototype-methods/no-prototype-methods return value.toString(); } return String(value); } module.exports = valueToString; },{}],36:[function(require,module,exports){ "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 hasPerformanceConstructorPrototype = _global.performance && _global.performance.constructor && _global.performance.constructor.prototype; 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) {