feat: Created a mini nodeJS server with NewMan for testing without PostMan GUI.

This will mimic a run in a CD/CI environment or docker container.
This commit is contained in:
Simon Priet
2021-09-08 14:01:19 +02:00
parent 5fbd7c88fa
commit e69a613a37
5610 changed files with 740417 additions and 3 deletions

66
node_modules/postman-sandbox/lib/sandbox/console.js generated vendored Normal file
View File

@@ -0,0 +1,66 @@
var teleportJS = require('teleport-javascript'),
arrayProtoSlice = Array.prototype.slice,
/**
* @constant
* @type {String}
*/
CONSOLE_EVENT_BASE = 'execution.console.',
/**
* List of functions that we expect and create for console
*
* @constant
* @type {String[]}
*/
logLevels = ['log', 'warn', 'debug', 'info', 'error'];
/**
* Replacer to be used with teleport-javascript to handle cases which are not
* handled by it.
*
* @param {String} key - Key of the property to replace
* @param {Any} value - Value of property to replace
* @return {Any} Replaced value
*/
function replacer (key, value) {
if (typeof value === 'function') {
const fnType = (value.constructor && value.constructor.name) ?
value.constructor.name : 'Function';
return value.name ? `[${fnType}: ${value.name}]` : `[${fnType}]`;
}
if (value instanceof WeakMap) {
return '[WeakMap]';
}
else if (value instanceof WeakSet) {
return '[WeakSet]';
}
else if (value instanceof ArrayBuffer) {
return `[ArrayBuffer { byteLength: ${value.byteLength} }]`;
}
return value;
}
function PostmanConsole (emitter, id, cursor, originalConsole) {
const dispatch = function (level) { // create a dispatch function that emits events
const args = arrayProtoSlice.call(arguments, 1);
if (originalConsole) {
// eslint-disable-next-line prefer-spread
originalConsole[level].apply(originalConsole, args);
}
emitter.dispatch(CONSOLE_EVENT_BASE + id, cursor, level, teleportJS.stringify(args, replacer));
};
// setup variants of the logger based on log levels
logLevels.forEach((name) => {
this[name] = dispatch.bind(emitter, name);
});
}
module.exports = PostmanConsole;

367
node_modules/postman-sandbox/lib/sandbox/cookie-jar.js generated vendored Normal file
View File

@@ -0,0 +1,367 @@
const CookieJar = require('tough-cookie').CookieJar,
ToughCookie = require('tough-cookie').Cookie,
PostmanCookie = require('postman-collection').Cookie,
PostmanCookieList = require('postman-collection').CookieList,
Url = require('postman-collection').Url,
FUNCTION = 'function',
OBJECT = 'object',
STRING = 'string',
/**
* Convert PostmanCookie Cookie instance to ToughCookie instance.
*
* @private
* @param {PostmanCookie} cookie - Postman Cookie instance
* @returns {ToughCookie} Tough Cookie instance
*/
serialize = function (cookie) {
if (!cookie) {
return;
}
return ToughCookie.fromJSON({
key: cookie.name || cookie.key,
value: cookie.value,
expires: cookie.expires,
maxAge: cookie.maxAge,
domain: cookie.domain,
path: cookie.path,
secure: cookie.secure,
httpOnly: cookie.httpOnly,
hostOnly: cookie.hostOnly,
extensions: cookie.extensions
});
},
/**
* Convert Tough Cookie instance to Electron Cookie instance.
*
* @private
* @param {ToughCookie} cookie - Tough Cookie instance
* @returns {ElectronCookie} Electron Cookie instance
*/
deserialize = function (cookie) {
if (!cookie) {
return;
}
return new PostmanCookie({
name: cookie.key,
value: cookie.value,
expires: cookie.expires === 'Infinity' ? null : cookie.expires,
maxAge: cookie.maxAge,
domain: cookie.domain,
path: cookie.path,
secure: cookie.secure,
httpOnly: cookie.httpOnly,
hostOnly: cookie.hostOnly,
extensions: cookie.extensions
});
},
/**
* Sanitize url object or string to Postman Url instance.
*
* @private
* @param {Object|String} url -
* @returns {Url|Null}
*/
sanitizeURL = function (url) {
if (Url.isUrl(url)) {
return url;
}
if (url && typeof url === STRING) {
return new Url(url);
}
return null;
},
/**
* Executes a provided function once for each array element.
*
* @note not completely asynchronous, don't compare with async.each
*
* @private
* @param {Array} items - Array of items to iterate over
* @param {Function} fn - An async function to apply to each item in items
* @param {Function} cb - A callback which is called when all iteratee functions have finished,
* or an error occurs
*/
forEachWithCallback = function (items, fn, cb) {
!cb && (cb = function () { /* (ಠ_ಠ) */ });
if (!(Array.isArray(items) && fn)) { return cb(); }
var index = 0,
totalItems = items.length,
next = function (err) {
if (err || index >= totalItems) {
return cb(err);
}
try {
fn.call(items, items[index++], next);
}
catch (error) {
return cb(error);
}
};
if (!totalItems) {
return cb();
}
next();
},
/**
* Helper function to handle callback.
*
* @private
* @param {Function} callback - Callback function
* @param {Error|String} err - Error or Error message
* @param {*} result -
*/
callbackHandler = function (callback, err, result) {
if (typeof callback !== FUNCTION) {
return;
}
if (err) {
return callback(err instanceof Error ? err : new Error(err));
}
callback(null, result);
},
/**
* Helper function to fetch a cookie with given name.
*
* @private
* @todo add CookieJar~getCookie to avoid this
*
* @param {CookieJar} jar - ToughCookie jar instance
* @param {String} url - Url string
* @param {String} name - Cookie name
* @param {Function} callback - Callback function
*/
getCookie = function (jar, url, name, callback) {
jar.getCookies(url, function (err, cookies) {
var i,
ii;
if (err) {
return callback(err);
}
if (!(cookies && cookies.length)) {
return callback(null, null);
}
for (i = 0, ii = cookies.length; i < ii; i++) {
if (cookies[i].key === name) {
return callback(null, cookies[i]);
}
}
callback(null, null);
});
};
class PostmanCookieJar {
/**
* @param {Object} cookieStore -
*/
constructor (cookieStore) {
this.store = cookieStore;
this.jar = new CookieJar(cookieStore, {
rejectPublicSuffixes: false,
looseMode: true
});
}
/**
* Get the cookie value with the given name.
*
* @param {String} url -
* @param {String} name -
* @param {Function} callback -
*/
get (url, name, callback) {
url = sanitizeURL(url);
if (!url) {
throw new TypeError('CookieJar.get() requires a valid url');
}
if (typeof callback !== FUNCTION) {
throw new TypeError('CookieJar.get() requires a callback function');
}
if (typeof name !== STRING) {
throw new TypeError('CookieJar.get() requires cookie name to be a string');
}
getCookie(this.jar, url.toString(true), name, function (err, cookie) {
if (err || !cookie) {
return callbackHandler(callback, err, null);
}
cookie = deserialize(cookie);
return callbackHandler(callback, null, cookie.valueOf());
});
}
/**
* Get all the cookies for the given URL.
*
* @param {String} url -
* @param {Object} [options] -
* @param {Function} callback -
*/
getAll (url, options, callback) {
url = sanitizeURL(url);
if (!url) {
throw new TypeError('CookieJar.getAll() requires a valid url');
}
if (typeof options === FUNCTION && !callback) {
callback = options;
options = {};
}
if (typeof callback !== FUNCTION) {
throw new TypeError('CookieJar.getAll() requires a callback function');
}
if (typeof options !== OBJECT) {
throw new TypeError('CookieJar.getAll() requires options to be an object');
}
options = {
// return HttpOnly cookies by default
http: Object.hasOwnProperty.call(options, 'http') ? Boolean(options.http) : true,
// if undefined, auto-detect from url
secure: Object.hasOwnProperty.call(options, 'secure') ? Boolean(options.secure) : undefined
};
this.jar.getCookies(url.toString(true), options, function (err, cookies) {
if (err) {
return callbackHandler(callback, err);
}
callbackHandler(callback, null, new PostmanCookieList(null, cookies && cookies.map(deserialize)));
});
}
/**
* Set or update a cookie.
*
* @param {String} url -
* @param {String|Object} name -
* @param {String|Function} [value] -
* @param {Function} [callback] -
*/
set (url, name, value, callback) {
url = sanitizeURL(url);
if (!url) {
throw new TypeError('CookieJar.set() requires a valid url');
}
if (typeof value === FUNCTION && !callback) {
callback = value;
value = null;
}
var cookie;
// @todo avoid else-if to reduce cyclomatic complexity
if (name && value) {
cookie = serialize({ name, value });
}
else if (typeof name === OBJECT) {
cookie = serialize(name);
}
else if (typeof name === STRING) {
cookie = name;
}
else {
throw new TypeError('CookieJar.set() requires a valid set cookie arguments');
}
this.jar.setCookie(cookie, url.toString(true), function (err, cookie) {
if (err) {
return callbackHandler(callback, err);
}
callbackHandler(callback, null, deserialize(cookie));
});
}
/**
* Remove single cookie with the given name.
*
* @param {String} url -
* @param {String} name -
* @param {Function} [callback] -
*/
unset (url, name, callback) {
url = sanitizeURL(url);
if (!url) {
throw new TypeError('CookieJar.unset() requires a valid url');
}
if (typeof name !== STRING) {
throw new TypeError('CookieJar.unset() requires cookie name to be a string');
}
var store = this.store;
getCookie(this.jar, url.toString(true), name, function (err, cookie) {
if (err || !cookie) {
return callbackHandler(callback, err);
}
store.removeCookie(cookie.domain, cookie.path, cookie.key, function (err) {
callbackHandler(callback, err);
});
});
}
/**
* Remove all the cookies for the given URL.
*
* @param {String} url -
* @param {Function} [callback] -
*/
clear (url, callback) {
url = sanitizeURL(url);
if (!url) {
throw new TypeError('CookieJar.clear() requires a valid url');
}
var store = this.store;
this.jar.getCookies(url.toString(true), function (err, cookies) {
if (err || !cookies) {
return callbackHandler(callback, err);
}
forEachWithCallback(cookies, function (cookie, next) {
store.removeCookie(cookie.domain, cookie.path, cookie.key, next);
}, function (err) {
callbackHandler(callback, err);
});
});
}
}
module.exports = PostmanCookieJar;

View File

@@ -0,0 +1,77 @@
const _ = require('lodash'),
Store = require('tough-cookie').Store,
Cookie = require('tough-cookie').Cookie,
EXECUTION_EVENT_BASE = 'execution.cookies.',
EVENT_STORE_ACTION = 'store',
STORE_METHODS = [
'findCookie', 'findCookies', 'putCookie', 'updateCookie',
'removeCookie', 'removeCookies', 'removeAllCookies', 'getAllCookies'
],
FUNCTION = 'function',
arrayProtoSlice = Array.prototype.slice;
class PostmanCookieStore extends Store {
constructor (id, emitter, timers) {
super();
this.id = id; // execution identifier
this.emitter = emitter;
this.timers = timers;
}
}
// Disable CookieJar's *Sync APIs
PostmanCookieStore.prototype.synchronous = false;
// attach a common handler to all store methods
STORE_METHODS.forEach(function (method) {
PostmanCookieStore.prototype[method] = function () {
const eventName = EXECUTION_EVENT_BASE + this.id;
let args,
eventId,
callback;
// fetch all the arguments passed to the method
args = arrayProtoSlice.call(arguments);
// adjust arguments length based on Store's prototype method
// eslint-disable-next-line lodash/path-style
args.length = _.get(Store.prototype, [method, 'length'], 0);
// move callback/last argument out of arguments
// this will be called when timer clears the event
callback = args.pop();
// set event for the callback
eventId = this.timers.setEvent(function (err, cookies) {
if (typeof callback !== FUNCTION) {
throw new TypeError('callback is not a function');
}
// methods: putCookie, updateCookie, removeCookie, removeCookies,
// removeAllCookies
// or, onError
if (err || !cookies) {
return callback(err);
}
// methods: findCookies, getAllCookies
if (Array.isArray(cookies)) {
return callback(err, cookies.map(function (cookie) {
return Cookie.fromJSON(cookie); // serialize cookie object
}));
}
// method: findCookie
callback(err, Cookie.fromJSON(cookies));
});
// finally, dispatch event over the bridge
this.emitter.dispatch(eventName, eventId, EVENT_STORE_ACTION, method, args);
};
});
module.exports = PostmanCookieStore;

View File

@@ -0,0 +1,68 @@
const _ = require('lodash'),
legacy = require('./postman-legacy-interface'),
NONLEGACY_SANDBOX_MARKERS = {
'"use sandbox2";': true,
'\'use sandbox2\';': true
};
module.exports = function (scope, code, execution, console, timers, pmapi, onAssertion) {
// if there is no code, then no point bubbling anything up
if (!(code && _.isString(code))) {
return timers.terminate();
}
// start by resetting the scope
scope.reset();
if (NONLEGACY_SANDBOX_MARKERS[code.substr(0, 15)]) {
// ensure any previously added global variables from legacy are torn down. side-effect is that if user
// explicitly created global variables with same name as legacy ones, they will be torn down too!
// for that reason, the setup function tags the scope and avoids tearing down an scope that was never setup
legacy.teardown(scope);
}
else {
// prepare legacy environment, which adds a tonne of global variables
legacy.setup(scope, execution);
}
// prepare the scope's environment variables
scope.import({
Buffer: require('buffer').Buffer,
// forward console
console: console,
// forward pm-api instance
/**
* The pm object encloses all information pertaining to the script being executed and
* allows one to access a copy of the request being sent or the response received.
* It also allows one to get and set environment and global variables.
*
* @type {Postman}
*/
pm: pmapi,
// import the timers
setTimeout: timers.setTimeout,
setInterval: timers.setInterval,
setImmediate: timers.setImmediate,
clearTimeout: timers.clearTimeout,
clearInterval: timers.clearInterval,
clearImmediate: timers.clearImmediate
});
scope.exec(code, function (err) {
// we check if the execution went async by determining the timer queue length at this time
execution.return.async = (timers.queueLength() > 0);
// call this hook to perform any post script execution tasks
legacy.finish(scope, pmapi, onAssertion);
// if timers are running, we do not need to proceed with any logic of completing execution. instead we wait
// for timer completion callback to fire
if (execution.return.async) {
return err && timers.error(err); // but if we had error, we pass it to async error handler
}
// at this stage, the script is a synchronous script, we simply forward whatever has come our way
timers.terminate(err);
});
};

163
node_modules/postman-sandbox/lib/sandbox/execute.js generated vendored Normal file
View File

@@ -0,0 +1,163 @@
const _ = require('lodash'),
Scope = require('uniscope'),
PostmanEvent = require('postman-collection').Event,
Execution = require('./execution'),
PostmanConsole = require('./console'),
PostmanTimers = require('./timers'),
PostmanAPI = require('./pmapi'),
PostmanCookieStore = require('./cookie-store'),
EXECUTION_RESULT_EVENT_BASE = 'execution.result.',
EXECUTION_REQUEST_EVENT_BASE = 'execution.request.',
EXECUTION_ERROR_EVENT = 'execution.error',
EXECUTION_ERROR_EVENT_BASE = 'execution.error.',
EXECUTION_ABORT_EVENT_BASE = 'execution.abort.',
EXECUTION_RESPONSE_EVENT_BASE = 'execution.response.',
EXECUTION_COOKIES_EVENT_BASE = 'execution.cookies.',
EXECUTION_ASSERTION_EVENT = 'execution.assertion',
EXECUTION_ASSERTION_EVENT_BASE = 'execution.assertion.',
executeContext = require('./execute-context');
module.exports = function (bridge, glob) {
// @note we use a common scope for all executions. this causes issues when scripts are run inside the sandbox
// in parallel, but we still use this way for the legacy "persistent" behaviour needed in environment
const scope = Scope.create({
eval: true,
ignore: ['require'],
block: ['bridge']
});
/**
* @param {String} id
* @param {Event} event
* @param {Object} context
* @param {Object} options
* @param {Boolean=} [options.debug]
* @param {Object=} [options.cursor]
* @param {Number=} [options.timeout]
*
* @note
* options also take in legacy properties: _itemId, _itemName
*/
bridge.on('execute', function (id, event, context, options) {
if (!(id && _.isString(id))) {
return bridge.dispatch('error', new Error('sandbox: execution identifier parameter(s) missing'));
}
!options && (options = {});
!context && (context = {});
event = (new PostmanEvent(event));
const executionEventName = EXECUTION_RESULT_EVENT_BASE + id,
executionRequestEventName = EXECUTION_REQUEST_EVENT_BASE + id,
errorEventName = EXECUTION_ERROR_EVENT_BASE + id,
abortEventName = EXECUTION_ABORT_EVENT_BASE + id,
responseEventName = EXECUTION_RESPONSE_EVENT_BASE + id,
cookiesEventName = EXECUTION_COOKIES_EVENT_BASE + id,
assertionEventName = EXECUTION_ASSERTION_EVENT_BASE + id,
// extract the code from event. The event can be the code itself and we know that if the event is of type
// string.
code = _.isFunction(event.script && event.script.toSource) && event.script.toSource(),
// create the execution object
execution = new Execution(id, event, context, options),
/**
* Dispatch assertions from `pm.test` or legacy `test` API.
*
* @private
* @param {Object[]} assertions -
* @param {String} assertions[].name -
* @param {Number} assertions[].index -
* @param {Object} assertions[].error -
* @param {Boolean} assertions[].async -
* @param {Boolean} assertions[].passed -
* @param {Boolean} assertions[].skipped -
*/
dispatchAssertions = function (assertions) {
// Legacy `test` API accumulates all the assertions and dispatches at once
// whereas, `pm.test` dispatch on every single assertion.
// For compatibility, dispatch the single assertion as an array.
!Array.isArray(assertions) && (assertions = [assertions]);
bridge.dispatch(assertionEventName, options.cursor, assertions);
bridge.dispatch(EXECUTION_ASSERTION_EVENT, options.cursor, assertions);
};
let waiting,
timers;
// create the controlled timers
timers = new PostmanTimers(null, function (err) {
if (err) { // propagate the error out of sandbox
bridge.dispatch(errorEventName, options.cursor, err);
bridge.dispatch(EXECUTION_ERROR_EVENT, options.cursor, err);
}
}, function () {
execution.return.async = true;
}, function (err, dnd) {
// clear timeout tracking timer
waiting && (waiting = clearTimeout(waiting));
// do not allow any more timers
if (timers) {
timers.seal();
timers.clearAll();
}
// remove listener of disconnection event
bridge.off(abortEventName);
bridge.off(responseEventName);
if (err) { // fire extra execution error event
bridge.dispatch(errorEventName, options.cursor, err);
bridge.dispatch(EXECUTION_ERROR_EVENT, options.cursor, err);
}
// @note delete response from the execution object to avoid dispatching
// the large response payload back due to performance reasons.
execution.response && (delete execution.response);
// fire the execution completion event
(dnd !== true) && bridge.dispatch(executionEventName, err || null, execution);
});
// if a timeout is set, we must ensure that all pending timers are cleared and an execution timeout event is
// triggered.
_.isFinite(options.timeout) && (waiting = setTimeout(function () {
timers.terminate(new Error('sandbox: ' +
(execution.return.async ? 'asynchronous' : 'synchronous') + ' script execution timeout'));
}, options.timeout));
// if an abort event is sent, compute cleanup and complete
bridge.on(abortEventName, function () {
timers.terminate(null, true);
});
// handle response event from outside sandbox
bridge.on(responseEventName, function (id, err, res, history) {
timers.clearEvent(id, err, res, history);
});
// handle cookies event from outside sandbox
bridge.on(cookiesEventName, function (id, err, res) {
timers.clearEvent(id, err, res);
});
// send control to the function that executes the context and prepares the scope
executeContext(scope, code, execution,
// if a console is sent, we use it. otherwise this also prevents erroneous referencing to any console
// inside this closure.
(new PostmanConsole(bridge, id, options.cursor, options.debug && glob.console)),
timers,
(
new PostmanAPI(execution, function (request, callback) {
var eventId = timers.setEvent(callback);
bridge.dispatch(executionRequestEventName, options.cursor, id, eventId, request);
}, dispatchAssertions, new PostmanCookieStore(id, bridge, timers))
),
dispatchAssertions);
});
};

85
node_modules/postman-sandbox/lib/sandbox/execution.js generated vendored Normal file
View File

@@ -0,0 +1,85 @@
const _ = require('lodash'),
sdk = require('postman-collection'),
PROPERTY = {
REQUEST: 'request',
SCRIPT: 'script',
DATA: 'data',
COOKIES: 'cookies',
RESPONSE: 'response'
},
TARGETS_WITH_REQUEST = {
test: true,
prerequest: true
},
TARGETS_WITH_RESPONSE = {
test: true
},
CONTEXT_VARIABLE_SCOPES = ['_variables', 'environment', 'collectionVariables', 'globals'],
trackingOptions = { autoCompact: true };
class Execution {
constructor (id, event, context, options) {
this.id = id;
this.target = event.listen || PROPERTY.SCRIPT;
this.legacy = options.legacy || {};
this.cursor = _.isObject(options.cursor) ? options.cursor : {};
this.data = _.get(context, PROPERTY.DATA, {});
this.cookies = new sdk.CookieList(null, context.cookies);
CONTEXT_VARIABLE_SCOPES.forEach((variableScope) => {
// normalize variable scope instances
this[variableScope] = sdk.VariableScope.isVariableScope(context[variableScope]) ?
context[variableScope] : new sdk.VariableScope(context[variableScope]);
// enable change tracking
this[variableScope].enableTracking(trackingOptions);
});
if (TARGETS_WITH_REQUEST[this.target] || _.has(context, PROPERTY.REQUEST)) {
/**
* @note:
* this reference is passed on as `pm.request`, pm api adds helper functions like `to` to `pm.request`
* sandbox overrides collection Request.prototype.toJSON to remove helpers before toJSON, see `purse.js`
*/
this.request = sdk.Request.isRequest(context.request) ? context.request : new sdk.Request(context.request);
}
if (TARGETS_WITH_RESPONSE[this.target] || _.has(context, PROPERTY.RESPONSE)) {
/**
* @note:
* this reference is passed on as `pm.response`, pm api adds helper functions like `to` to `pm.response`
* sandbox overrides collection Response.prototype.toJSON to remove helpers before toJSON, see `purse.js`
*/
this.response = sdk.Response.isResponse(context.response) ?
context.response : new sdk.Response(context.response);
}
/**
* @typedef {Object} Return
*
* @property {Boolean} async - true if the executed script was async, false otherwise
* @property {Visualizer} visualizer - visualizer data
* @property {*} nextRequest - next request to send
*/
this.return = {};
}
toJSON () {
return _.mapValues(this, function (value) {
// if there is no specific json serialiser, return the raw value
if (!_.isFunction(value && value.toJSON)) {
return value;
}
return value.toJSON();
});
}
}
module.exports = Execution;

73
node_modules/postman-sandbox/lib/sandbox/index.js generated vendored Normal file
View File

@@ -0,0 +1,73 @@
/**!
* @license Copyright 2016 Postdot Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*
* This file is the Postman scripting sandbox's bootstrap code and would during module usage be exported as part of npm
* cache and deployed for ease of use and performance improvements.
*
* @note
* This file runs within Node and browser sandboxes and standard node aspects may not 100% apply
*/
/* global bridge */
// Although we execute the user code in a well-defined scope using the uniscope
// module but still to cutoff the reference to the globally available properties
// we sanitize the global scope by deleting the forbidden properties in this UVM
// and create a secure sandboxed environment.
// @note this is executed at the very beginning of the sandbox code to make sure
// non of the dependency can keep a reference to a global property.
// @note since this mutates the global scope, it's possible to mess-up as we
// update our dependencies.
(function recreatingTheUniverse () {
var contextObject = this,
// 1. allow all the uniscope allowed globals
allowedGlobals = require('uniscope/lib/allowed-globals').concat([
// 2. allow properties which can be controlled/ignored using uniscope
'require', 'eval', 'console',
// 3. allow uvm internals because these will be cleared by uvm itself at the end.
// make sure any new property added in uvm firmware is allowed here as well.
'bridge', '__uvm_emit', '__uvm_dispatch', '__uvm_addEventListener',
// 4.allow all the timer methods
'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'setImmediate', 'clearImmediate'
]),
deleteProperty = function (key) {
// directly delete the property without setting it to `null` or `undefined`
// because a few properties in browser context breaks the sandbox.
// @note non-configurable keys are not deleted.
// eslint-disable-next-line lodash/prefer-includes
allowedGlobals.indexOf(key) === -1 && delete contextObject[key];
};
do {
// delete all forbidden properties (including non-enumerable)
Object.getOwnPropertyNames(contextObject).forEach(deleteProperty);
// keep looking through the prototype chain until we reach the Object prototype
// @note this deletes the constructor as well to make sure one can't recreate the same scope
contextObject = Object.getPrototypeOf(contextObject);
} while (contextObject && contextObject.constructor !== Object);
}());
// do include json purse
require('./purse');
// setup the ping-pong and execute routines
bridge.on('ping', require('./ping').listener('pong'));
// initialise execution
require('./execute')(bridge, {
console: (typeof console !== 'undefined' ? console : null),
window: (typeof window !== 'undefined' ? window : null)
});
// We don't need direct access to the global bridge once it's part of execution closure.
// eslint-disable-next-line no-global-assign, no-implicit-globals, no-delete-var
bridge = undefined; delete bridge;

8
node_modules/postman-sandbox/lib/sandbox/ping.js generated vendored Normal file
View File

@@ -0,0 +1,8 @@
module.exports = {
listener (pong) {
return function (payload) {
this.dispatch(pong, payload);
};
}
};

View File

@@ -0,0 +1,135 @@
/**
* @fileOverview
*
* This module externally sets up the test runner on pm api. Essentially, it does not know the insides of pm-api and
* does the job completely from outside with minimal external dependency
*/
const FUNCTION = 'function';
/**
* @module {PMAPI~setupTestRunner}
* @private
*
* @param {PMAPI} pm - an instance of PM API that it needs
* @param {Function} onAssertionComplete - is the trigger function that is called every time a test is executed and it
* receives the AssertionInfo object outlining details of the assertion
*/
module.exports = function (pm, onAssertionComplete) {
var assertionIndex = 0,
/**
* Returns an object that represents data coming out of an assertion.
*
* @note This is put in a function since this needs to be done from a number of place and having a single
* function reduces the chance of bugs
*
* @param {String} name -
* @param {Boolean} skipped -
*
* @returns {PMAPI~AssertionInfo}
*/
getAssertionObject = function (name, skipped) {
/**
* @typeDef {AssertionInfo}
* @private
*/
return {
name: String(name),
async: false,
skipped: Boolean(skipped),
passed: true,
error: null,
index: assertionIndex++ // increment the assertion counter (do it before asserting)
};
},
/**
* Simple function to mark an assertion as failed
*
* @private
*
* @note This is put in a function since this needs to be done from a number of place and having a single
* function reduces the chance of bugs
*
* @param {Object} assertionData -
* @param {*} err -
*/
markAssertionAsFailure = function (assertionData, err) {
assertionData.error = err;
assertionData.passed = false;
};
/**
* @param {String} name -
* @param {Function} assert -
* @chainable
*/
pm.test = function (name, assert) {
var assertionData = getAssertionObject(name, false);
// if there is no assertion function, we simply move on
if (typeof assert !== FUNCTION) {
onAssertionComplete(assertionData);
return pm;
}
// if a callback function was sent, then we know that the test is asynchronous
if (assert.length) {
try {
assertionData.async = true; // flag that this was an async test (would be useful later)
// we execute assertion, but pass it a completion function, which, in turn, raises the completion
// event. we do not need to worry about timers here since we are assuming that some timer within the
// sandbox had actually been the source of async calls and would take care of this
assert(function (err) {
// at first we double check that no synchronous error has happened from the catch block below
if (assertionData.error && assertionData.passed === false) {
return;
}
// user triggered a failure of the assertion, so we mark it the same
if (err) {
markAssertionAsFailure(assertionData, err);
}
onAssertionComplete(assertionData);
});
}
// in case a synchronous error occurs in the the async assertion, we still bail out.
catch (e) {
markAssertionAsFailure(assertionData, e);
onAssertionComplete(assertionData);
}
}
// if the assertion function does not expect a callback, we synchronously execute the same
else {
try { assert(); }
catch (e) {
markAssertionAsFailure(assertionData, e);
}
onAssertionComplete(assertionData);
}
return pm; // make it chainable
};
/**
* @param {String} name -
* @chainable
*/
pm.test.skip = function (name) {
// trigger the assertion events with skips
onAssertionComplete(getAssertionObject(name, true));
return pm; // chainable
};
/**
* @returns {Number}
*/
pm.test.index = function () {
return assertionIndex;
};
};

285
node_modules/postman-sandbox/lib/sandbox/pmapi.js generated vendored Normal file
View File

@@ -0,0 +1,285 @@
const _ = require('lodash'),
Ajv = require('ajv'),
sdk = require('postman-collection'),
PostmanCookieJar = require('./cookie-jar'),
VariableScope = sdk.VariableScope,
PostmanRequest = sdk.Request,
PostmanResponse = sdk.Response,
PostmanCookieList = sdk.CookieList,
chai = require('chai'),
/**
* Use this function to assign readonly properties to an object
*
* @private
*
* @param {Object} obj -
* @param {Object} properties -
*/
_assignDefinedReadonly = function (obj, properties) {
var config = {
writable: false
},
prop;
for (prop in properties) {
if (Object.hasOwnProperty.call(properties, prop) && (properties[prop] !== undefined)) {
config.value = properties[prop];
Object.defineProperty(obj, prop, config);
}
}
return obj; // chainable
},
setupTestRunner = require('./pmapi-setup-runner');
/**
* @constructor
*
* @param {Execution} execution -
* @param {Function} onRequest -
* @param {Function} onAssertion -
* @param {Object} cookieStore -
*/
function Postman (execution, onRequest, onAssertion, cookieStore) {
// @todo - ensure runtime passes data in a scope format
let iterationData = new VariableScope();
iterationData.syncVariablesFrom(execution.data);
// instead of creating new instance of variableScope,
// reuse one so that any changes made through pm.variables.set() is directly reflected
execution._variables.addLayer(iterationData.values);
execution._variables.addLayer(execution.environment.values);
execution._variables.addLayer(execution.collectionVariables.values);
execution._variables.addLayer(execution.globals.values);
execution.cookies && (execution.cookies.jar = function () {
return new PostmanCookieJar(cookieStore);
});
_assignDefinedReadonly(this, /** @lends Postman.prototype */ {
/**
* Contains information pertaining to the script execution
*
* @interface Info
*/
/**
* The pm.info object contains information pertaining to the script being executed.
* Useful information such as the request name, request Id, and iteration count are
* stored inside of this object.
*
* @type {Info}
*/
info: _assignDefinedReadonly({}, /** @lends Info */ {
/**
* Contains information whether the script being executed is a "prerequest" or a "test" script.
*
* @type {string}
* @instance
*/
eventName: execution.target,
/**
* Is the value of the current iteration being run.
*
* @type {number}
* @instance
*/
iteration: execution.cursor.iteration,
/**
* Is the total number of iterations that are scheduled to run.
*
* @type {number}
* @instance
*/
iterationCount: execution.cursor.cycles,
/**
* The saved name of the individual request being run.
*
* @type {string}
* @instance
*/
requestName: execution.legacy._itemName,
/**
* The unique guid that identifies the request being run.
*
* @type {string}
* @instance
*/
requestId: execution.legacy._itemId
}),
/**
* @type {VariableScope}
*/
globals: execution.globals,
/**
* @type {VariableScope}
*/
environment: execution.environment,
/**
* @type {VariableScope}
*/
collectionVariables: execution.collectionVariables,
/**
* @type {VariableScope}
*/
variables: execution._variables,
/**
* The iterationData object contains data from the data file provided during a collection run.
*
* @type {VariableScope}
*/
iterationData: iterationData,
/**
* The request object inside pm is a representation of the request for which this script is being run.
* For a pre-request script, this is the request that is about to be sent and when in a test script,
* this is the representation of the request that was sent.
*
* @type {Request}
*/
request: execution.request,
/**
* Inside the test scripts, the pm.response object contains all information pertaining
* to the response that was received.
*
* @type {Response}
* @customexclude true
*/
response: execution.response,
/**
* The cookies object contains a list of cookies that are associated with the domain
* to which the request was made.
*
* @type {CookieList}
*/
cookies: execution.cookies,
/**
* @interface Visualizer
*/
/**
* @type {Visualizer}
*/
visualizer: /** @lends Visualizer */ {
/**
* Set visualizer template and its options
*
* @instance
* @param {String} template - visualisation layout in form of template
* @param {Object} [data] - data object to be used in template
* @param {Object} [options] - options to use while processing the template
*/
set (template, data, options) {
if (typeof template !== 'string') {
throw new Error(`Invalid template. Template must be of type string, found ${typeof template}`);
}
if (data && typeof data !== 'object') {
throw new Error(`Invalid data. Data must be an object, found ${typeof data}`);
}
if (options && typeof options !== 'object') {
throw new Error(`Invalid options. Options must be an object, found ${typeof options}`);
}
/**
*
* @property {String} template - template string
* @property {Object} data - data to use while processing template
* @property {Object} options - options to use while processing template
*/
execution.return.visualizer = {
template,
data,
options
};
},
/**
* Clear all visualizer data
*
* @instance
*/
clear () {
execution.return.visualizer = undefined;
}
}
});
// extend pm api with test runner abilities
setupTestRunner(this, onAssertion);
// add response assertions
if (this.response) {
// these are removed before serializing see `purse.js`
Object.defineProperty(this.response, 'to', {
get () {
return chai.expect(this).to;
}
});
}
// add request assertions
if (this.request) {
// these are removed before serializing see `purse.js`
Object.defineProperty(this.request, 'to', {
get () {
return chai.expect(this).to;
}
});
}
/**
* Allows one to send request from script asynchronously.
*
* @param {Request|String} req -
* @param {Function} callback -
*/
this.sendRequest = function (req, callback) {
var self = this;
if (!req) {
return _.isFunction(callback) && callback.call(self, new Error('sendrequest: nothing to request'));
}
onRequest(PostmanRequest.isRequest(req) ? req : (new PostmanRequest(req)), function (err, resp, history) {
if (history && !PostmanCookieList.isCookieList(history.cookies)) {
history.cookies = new PostmanCookieList({}, history.cookies);
}
_.isFunction(callback) && callback.call(self, err,
PostmanResponse.isResponse(resp) ? resp : (new PostmanResponse(resp)),
history);
});
return self;
};
iterationData = null; // precautionary
}
// expose chai assertion library via prototype
/**
* @type {Chai.ExpectStatic}
*/
Postman.prototype.expect = chai.expect;
// make chai use postman extension
chai.use(require('chai-postman')(sdk, _, Ajv));
// export
module.exports = Postman;

View File

@@ -0,0 +1,420 @@
/* eslint-disable max-classes-per-file */
const _ = require('lodash'),
scopeLibraries = {
JSON: require('liquid-json'),
_: require('lodash3').noConflict(),
CryptoJS: require('crypto-js'),
atob: require('atob'),
btoa: require('btoa'),
tv4: require('tv4'),
xml2Json: require('./xml2Json'),
Backbone: require('backbone'),
cheerio: require('cheerio')
},
LEGACY_GLOBS = [
'tests', 'globals', 'environment', 'data', 'request', 'responseCookies', 'responseHeaders', 'responseTime',
'responseCode', 'responseBody', 'iteration', 'postman',
// scope libraries
'JSON', '_', 'CryptoJS', 'atob', 'btoa', 'tv4', 'xml2Json', 'Backbone', 'cheerio'
],
E = '',
FUNCTION = 'function',
TARGET_TEST = 'test',
LEGACY_ASSERTION_ERROR_MESSAGE_PREFIX = 'expected ',
LEGACY_ASSERTION_ERROR_MESSAGE_SUFFIX = ' to be truthy',
/**
* Different modes for a request body.
*
* @enum {String}
*/
REQUEST_MODES = {
RAW: 'raw',
URLENCODED: 'urlencoded',
FORMDATA: 'formdata',
FILE: 'file'
};
function getRequestBody (request) {
var mode = _.get(request, 'body.mode'),
body = _.get(request, 'body'),
empty = body ? body.isEmpty() : true,
content,
computedBody;
if (empty) {
return;
}
content = body[mode];
if (_.isFunction(content && content.all)) {
content = content.all();
}
if (mode === REQUEST_MODES.RAW) {
computedBody = {
body: content
};
}
else if (mode === REQUEST_MODES.URLENCODED) {
computedBody = {
form: _.reduce(content, function (accumulator, param) {
if (param.disabled) { return accumulator; }
// This is actually pretty simple,
// If the variable already exists in the accumulator, we need to make the value an Array with
// all the variable values inside it.
if (accumulator[param.key]) {
_.isArray(accumulator[param.key]) ? accumulator[param.key].push(param.value) :
(accumulator[param.key] = [accumulator[param.key], param.value]);
}
else {
accumulator[param.key] = param.value;
}
return accumulator;
}, {})
};
}
else if (request.body.mode === REQUEST_MODES.FORMDATA) {
computedBody = {
formData: _.reduce(content, function (accumulator, param) {
if (param.disabled) { return accumulator; }
// This is actually pretty simple,
// If the variable already exists in the accumulator, we need to make the value an Array with
// all the variable values inside it.
if (accumulator[param.key]) {
_.isArray(accumulator[param.key]) ? accumulator[param.key].push(param.value) :
(accumulator[param.key] = [accumulator[param.key], param.value]);
}
else {
accumulator[param.key] = param.value;
}
return accumulator;
}, {})
};
}
else if (request.body.mode === REQUEST_MODES.FILE) {
computedBody = {
body: _.get(request, 'body.file.content')
};
}
return computedBody;
}
/**
* Raises a single assertion event with an array of assertions from legacy `tests` object.
*
* @param {Uniscope} scope -
* @param {Object} pmapi -
* @param {Function} onAssertion -
*/
function raiseAssertionEvent (scope, pmapi, onAssertion) {
var tests = scope._imports && scope._imports.tests,
assertionIndex = pmapi.test.index(),
assertions;
if (_.isEmpty(tests)) {
return;
}
assertions = _.map(tests, function (value, key) {
var assertionName = String(key),
passed = Boolean(value),
assertionError = null;
// fake an assertion error for legacy tests
if (!passed) {
assertionError = new Error(LEGACY_ASSERTION_ERROR_MESSAGE_PREFIX +
String(value) + LEGACY_ASSERTION_ERROR_MESSAGE_SUFFIX);
assertionError.name = 'AssertionError';
}
// @todo Move getAssertionObject function from pmapi-setup-runner.js to a common place and reuse it here too
return {
name: assertionName,
skipped: false,
passed: passed,
error: assertionError,
index: assertionIndex++
};
});
onAssertion(assertions);
}
class PostmanLegacyInterface {
/**
* @param {Object} execution -
* @param {Object} globalvars -
*/
constructor (execution, globalvars) {
this.__execution = execution;
this.__environment = globalvars.environment;
this.__globals = globalvars.globals;
}
setEnvironmentVariable (key, value) {
if ((value === false || value) && typeof (value && value.toString) === FUNCTION) {
value = value.toString();
}
this.__environment[key] = value;
return this.__execution.environment.set(key, value);
}
getEnvironmentVariable (key) {
return this.__execution.environment.get(key);
}
clearEnvironmentVariables () {
for (var prop in this.__environment) {
if (Object.hasOwnProperty.call(this.__environment, prop)) {
delete this.__environment[prop];
}
}
return this.__execution.environment.clear();
}
clearEnvironmentVariable (key) {
key && (delete this.__environment[key]);
return this.__execution.environment.unset(key);
}
setGlobalVariable (key, value) {
if ((value === false || value) && typeof (value && value.toString) === FUNCTION) {
value = value.toString();
}
this.__globals[key] = value;
return this.__execution.globals.set(key, value);
}
getGlobalVariable (key) {
return this.__execution.globals.get(key);
}
clearGlobalVariables () {
for (var prop in this.__globals) {
if (Object.hasOwnProperty.call(this.__globals, prop)) {
delete this.__globals[prop];
}
}
return this.__execution.globals.clear();
}
clearGlobalVariable (key) {
key && (delete this.__globals[key]);
return this.__execution.globals.unset(key);
}
setNextRequest (what) {
this.__execution.return && (this.__execution.return.nextRequest = what);
}
}
/**
* @constructor
* @extends {PostmanLegacyInterface}
*/
class PostmanLegacyTestInterface extends PostmanLegacyInterface {
/**
* @param {String} cookieName -
* @returns {Object}
*/
getResponseCookie (cookieName) {
return this.__execution.cookies ? this.__execution.cookies.one(String(cookieName)) : undefined;
}
/**
* @param {String} headerName -
* @returns {String}
*/
getResponseHeader (headerName) {
var header = (this.__execution.response && this.__execution.response.headers) &&
this.__execution.response.headers.one(headerName);
return header ? header.value : undefined;
}
}
module.exports = {
/**
*
* @param {Uniscope} scope -
* @param {Execution} execution -
*
* @note ensure that globalvars variables added here are added as part of the LEGACY_GLOBS array
*/
setup (scope, execution) {
/**
* @name SandboxGlobals
* @type {Object}
*/
var globalvars = _.assign({}, scopeLibraries);
// set global variables that are exposed in legacy interface
// ---------------------------------------------------------
// 1. set the tests object (irrespective of target)
/**
* Store your assertions in this object
*
* @memberOf SandboxGlobals
* @type {Object}
*/
globalvars.tests = {};
// 2. set common environment, globals and data
/**
* All global variables at the initial stages when the script ran
*
* @memberOf SandboxGlobals
* @type {Object}
*/
globalvars.globals = execution.globals.syncVariablesTo();
/**
* All environment variables at the initial stages when script ran
*
* @memberOf SandboxGlobals
* @type {Object}
*/
globalvars.environment = execution.environment.syncVariablesTo();
/**
* The data object if it was passed during a collection run
*
* @memberOf SandboxGlobals
* @type {Object}
*/
globalvars.data = execution.data || (execution.data = {});
// 3. set the request object in legacy structure
/**
* The request that will be sent (or has been sent)
*
* @memberOf SandboxGlobals
* @type {Object}
*/
globalvars.request = execution.request ? {
id: execution.legacy ? execution.legacy._itemId : undefined,
name: execution.legacy ? execution.legacy._itemName : undefined,
description: execution.request.description ?
execution.request.description.toString() : undefined,
headers: execution.request.headers.toObject(true, false, true, true),
method: execution.request.method,
url: execution.request.url.toString(),
data: (function (request) {
var body = getRequestBody(request);
return body ? (body.form || body.formData || body.body || {}) : {};
}(execution.request))
} : {};
// 4. set the response related objects
if (execution.target === TARGET_TEST) {
/**
* Stores the response cookies
*
* @memberOf SandboxGlobals
* @type {Array.<Object>}
*/
globalvars.responseCookies = execution.cookies || [];
/**
* Stores the response headers with the keys being case sensitive
*
* @memberOf SandboxGlobals
* @type {Array.<Object>}
*/
globalvars.responseHeaders = {};
execution.response && execution.response.headers.each(function (header) {
header && !header.disabled && (globalvars.responseHeaders[header.key] = header.value);
});
/**
* @memberOf SandboxGlobals
* @type {Number}
*/
globalvars.responseTime = execution.response ? execution.response.responseTime : NaN;
/**
* @memberOf SandboxGlobals
* @type {Number}
*/
globalvars.responseCode = execution.response ? _.clone(execution.response.details()) : {
code: NaN,
name: E,
details: E
};
/**
* @memberOf SandboxGlobals
* @type {String}
*/
globalvars.responseBody = execution.response ? execution.response.text() : undefined;
}
// 5. add the iteration information
globalvars.iteration = _.isObject(execution.cursor) ? execution.cursor.iteration : 0;
// 6. create the postman interface object
/**
* @memberOf SandboxGlobals
* @type {PostmanLegacyInterface}
*/
globalvars.postman = new (execution.target === TARGET_TEST ?
PostmanLegacyTestInterface : PostmanLegacyInterface)(execution, globalvars);
// make a final pass to ensure that the global variables are present
// all the globals are now added to scope
scope.import(globalvars);
globalvars = null; // dereference
// add a flag to ensure that when teardown is called, it does not tear down a scope that was never setup
scope.__postman_legacy_setup = true;
},
teardown (scope) {
if (!scope.__postman_legacy_setup) {
return;
}
for (var i = 0, ii = LEGACY_GLOBS.length; i < ii; i++) {
scope.unset(LEGACY_GLOBS[i]);
}
scope.__postman_legacy_setup = false;
},
/**
* This is the place where we should put all the tasks
* that need to be executed after the completion of script execution
*
* @param {Uniscope} scope -
* @param {Object} pmapi -
* @param {Function} onAssertion -
*/
finish (scope, pmapi, onAssertion) {
if (!scope.__postman_legacy_setup) {
return;
}
raiseAssertionEvent(scope, pmapi, onAssertion);
}
};

53
node_modules/postman-sandbox/lib/sandbox/purse.js generated vendored Normal file
View File

@@ -0,0 +1,53 @@
/**
* This module adds `.toJSON` to prototypes of objects that does not behave well with JSON.stringify() This aides in
* accurate transport of information between IPC
*
*/
try {
Error && (Error.prototype.toJSON = function () { // eslint-disable-line no-extend-native
return {
type: 'Error',
name: this.name,
message: this.message
};
});
}
catch (e) {} // eslint-disable-line no-empty
const { Request, Response } = require('postman-collection');
/**
* We override toJSON to not export additional helpers that sandbox adds to pm.request and pm.response.
*/
try {
Request.prototype.toJSON = (function (superToJSON) { // eslint-disable-line no-extend-native
return function () {
var tmp = this.to,
json;
// remove properties added by sandbox before doing a toJSON
delete this.to;
json = superToJSON.apply(this, arguments);
this.to = tmp;
return json;
};
}(Request.prototype.toJSON));
Response.prototype.toJSON = (function (superToJSON) { // eslint-disable-line no-extend-native
return function () {
var tmp = this.to,
json;
// remove properties added by sandbox before doing a toJSON
delete this.to;
json = superToJSON.apply(this, arguments);
this.to = tmp;
return json;
};
}(Response.prototype.toJSON));
}
catch (e) {} // eslint-disable-line no-empty

309
node_modules/postman-sandbox/lib/sandbox/timers.js generated vendored Normal file
View File

@@ -0,0 +1,309 @@
/**
* @fileoverview This file contains the module that is required to enable specialised timers that have better control
* on a global level.
*
* @todo - the architecture of this sucks even if this "works".
* - the way to compute firing of start and end events suck
* - basically this needs a redo with more "engineering" put into it
*/
const /**
*
* @constant {String}
*/
FUNCTION = 'function',
/**
* The set of timer function names. We use this array to define common behaviour of all setters and clearer timer
* functions
*
* @constant {Array.<String>}
*/
timerFunctionNames = ['Timeout', 'Interval', 'Immediate', 'Event'],
/**
* This object defines a set of timer function names that are trigerred a number of times instead of a single time.
* Such timers, when placed in generic rules, needs special attention.
*
* @constant {Array.<Boolean>}
*/
multiFireTimerFunctions = {
Interval: true
},
/**
* This object defines a set of function timer names that do not fire based on any pre-set duration or interval.
* Such timers, when placed in generic rules, needs special attention.
*
* @constant {Array.<Boolean>}
*/
staticTimerFunctions = {
Event: true
},
/**
* A local copy of Slice function of Array
*
* @constant {Function}
*/
arrayProtoSlice = Array.prototype.slice,
/**
* This object holds the current global timers
*
* @extends Timers
*
* @note This is a very important piece of code from compatibility standpoint.
* The global timers need to be returned as a function that does not hold reference to the scope
* and does not retain references to scope. Aditionally, the invocation of the timer function is
* done without changing the scope to avoid Illegal Invocation errors.
*
* `timerFunctionNames` returns the suffixes of all timer operations that needs a
* a setter and clear method.
*/
defaultTimers = timerFunctionNames.reduce(function (timers, name) {
var
/**
* Check if global setter function is available
*
* @private
* @type {Boolean}
*/
// eslint-disable-next-line no-new-func
isGlobalSetterAvailable = (new Function(`return typeof set${name} === 'function'`))(),
/**
* Check if global clear function is available
*
* @private
* @type {Boolean}
*/
// eslint-disable-next-line no-new-func
isGlobalClearAvailable = (new Function(`return typeof clear${name} === 'function'`))();
if (isGlobalSetterAvailable) {
// eslint-disable-next-line no-new-func
timers[('set' + name)] = (new Function(`return function (fn, ms) { return set${name}(fn, ms); }`))();
}
if (isGlobalClearAvailable) {
// eslint-disable-next-line no-new-func
timers[('clear' + name)] = (new Function(`return function (id) { return clear${name}(id); }`))();
}
return timers;
}, {});
/**
* @constructor
*
* @param {Object} [delegations] -
* @param {Function} [onError] -
* @param {Function} [onAnyTimerStart] -
* @param {Function} [onAllTimerEnd] -
*/
function Timerz (delegations, onError, onAnyTimerStart, onAllTimerEnd) {
var /**
* Holds the present timers, either delegated or defaults
*
* @extends Timers
*/
timers = delegations || defaultTimers,
dummyContext = {},
total = 0, // accumulator to keep track of total timers
pending = 0, // counters to keep track of running timers
sealed = false, // flag that stops all new timer additions
wentAsync = false,
computeTimerEvents;
// do special handling to enable emulation of immediate timers in hosts that lacks them
if (typeof timers.setImmediate !== FUNCTION) {
timers.setImmediate = function (callback) {
return timers.setTimeout(callback, 0);
};
timers.clearImmediate = function (id) {
return timers.clearTimeout(id);
};
}
// write special handlers for event based timers if the delegations don't contain one
(typeof timers.setEvent !== FUNCTION) && (function () {
var events = {},
total = 0;
timers.setEvent = function (callback) {
var id = ++total;
events[id] = callback;
return id;
};
timers.clearEvent = function (id) {
var cb = events[id];
delete events[id];
(typeof cb === FUNCTION) && cb.apply(dummyContext, arrayProtoSlice.call(arguments, 1));
};
timers.clearAllEvents = function () {
Object.keys(events).forEach(function (prop) {
delete events[prop];
});
};
}());
// create a function that decides whether to fire appropriate callbacks
computeTimerEvents = function (increment, clearing) {
increment && (pending += increment);
if (pending === 0 && computeTimerEvents.started) {
!clearing && (typeof onAllTimerEnd === FUNCTION) && onAllTimerEnd();
computeTimerEvents.started = false;
return;
}
if (pending > 0 && !computeTimerEvents.started) {
!clearing && (typeof onAnyTimerStart === FUNCTION) && onAnyTimerStart();
computeTimerEvents.started = true;
}
};
// iterate through the timer variants and create common setter and clearer function behaviours for each of them.
timerFunctionNames.forEach(function (name) {
// create an accumulator for all timer references
var running = {};
// create the setter function for the timer
this[('set' + name)] = function (callback) {
// it is pointless to proceed with setter if there is no callback to execute
if (sealed || typeof callback !== FUNCTION) {
return;
}
var id = ++total, // get hold of the next timer id
args = arrayProtoSlice.call(arguments);
args[0] = function () {
wentAsync = true; // mark that we did go async once. this will ensure we do not pass erroneous events
// call the actual callback with a dummy context
try { callback.apply(dummyContext, staticTimerFunctions[name] ? arguments : null); }
catch (e) { onError && onError(e); }
// interval timers can only be cleared using clearXYZ function and hence we need not do anything
// except call the timer
if (staticTimerFunctions[name] || multiFireTimerFunctions[name]) {
// do not modify counter during interval type events
computeTimerEvents();
}
// when this is fired, the timer dies, so we decrement tracking counters and delete
// irq references
else {
computeTimerEvents(-1);
delete running[id];
}
};
// for static timers
staticTimerFunctions[name] && (wentAsync = true);
// call the underlying timer function and keep a track of its irq
running[id] = timers[('set' + name)].apply(this, args);
args = null; // precaution
// increment the counter and return the tracking ID to be used to pass on to clearXYZ function
computeTimerEvents(1);
return id;
};
// create the clear function of the timer
this[('clear' + name)] = function (id) {
var underLyingId = running[id],
args;
// it is pointless and erroenous to proceed in case it seems that it is no longer running
if (sealed || !underLyingId) {
return;
}
// prepare args to be forwarded to clear function
args = arrayProtoSlice.call(arguments);
args[0] = underLyingId;
delete running[id];
// fire the underlying clearing function
try { timers['clear' + name].apply(dummyContext, args); }
catch (e) { onError(e); }
// decrement counters and call the clearing timer function
computeTimerEvents(-1, !wentAsync);
args = underLyingId = null; // just a precaution
};
// create a sugar function to clear all running timers of this category
// @todo: decide how to handle clearing for underlying delegated timers, if they are instances of Timerz itself.
if (typeof timers[('clearAll' + name + 's')] === FUNCTION) {
// if native timers have a function to clear all timers, then use it
this[('clearAll' + name + 's')] = function () {
timers[('clearAll' + name + 's')]();
Object.keys(running).forEach(function () {
computeTimerEvents(-1, true);
});
};
}
else {
this[('clearAll' + name + 's')] = function () {
Object.keys(running).forEach(function (id) {
computeTimerEvents(-1, true);
// run clear functions except for static timers
timers['clear' + name](running[id]);
});
};
}
}.bind(this));
/**
* @memberof Timerz.prototype
* @returns {Number}
*/
this.queueLength = function () {
return pending;
};
/**
* @memberof Timerz.prototype
*/
this.clearAll = function () {
// call all internal timer clearAll function variants
timerFunctionNames.forEach(function (name) {
this[('clearAll' + name + 's')]();
}.bind(this));
};
/**
* @memberof Timerz.prototype
*/
this.seal = function () {
sealed = true;
};
this.error = function (err) {
return onError.call(dummyContext, err);
};
this.terminate = function () {
this.seal();
this.clearAll();
return onAllTimerEnd.apply(dummyContext, arguments);
};
}
module.exports = Timerz;

23
node_modules/postman-sandbox/lib/sandbox/xml2Json.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
const xml2js = require('xml2js'),
/**
* @constant
* @type {Object}
*/
xml2jsOptions = {
explicitArray: false,
// this ensures that it works in the sync sandbox we currently have in the app
async: false,
trim: true,
mergeAttrs: false
};
module.exports = function (string) {
var JSON = {};
xml2js.parseString(string, xml2jsOptions, function (_, result) { // @todo - see who swallows the error
JSON = result;
});
return JSON;
};