var _ = require('../util').lodash,
Property = require('./property').Property,
PropertyList = require('./property-list').PropertyList,
EventList = require('./event-list').EventList,
Item = require('./item').Item,
Request = require('./request').Request,
RequestAuth = require('./request-auth').RequestAuth,
ItemGroup,
/**
* @private
* @type {String}
*/
OBJECT = 'object';
/**
* The following defines the object (or JSON) structure that one can pass to the ItemGroup while creating a new
* ItemGroup instance. This is also the object structure returned when `.toJSON()` is called on an ItemGroup instance.
*
* @typedef ItemGroup.definition
* @property {Array<ItemGroup.definition|Item.definition>=} [item]
* @property {RequestAuth.definition=} [auth]
* @property {Array<Event.definition>=} [event]
*
* @example
* {
* "name": "Echo Get Requests",
* "id": "echo-get-requests",
* "item": [{
* "request": "https://postman-echo.com/get"
* }, {
* "request": "https://postman-echo.com/headers"
* }],
* "auth": {
* "type": "basic",
* "basic": {
* "username": "jean",
* "password": "{{somethingsecret}}"
* }
* },
* "event": [{
* "listen": "prerequest",
* "script": {
* "type": "text/javascript",
* "exec": "console.log(new Date())"
* }
* }]
* }
*/
_.inherit((
/**
* An ItemGroup represents a composite list of {@link Item} or ItemGroup. In terms of Postman App, ItemGroup
* represents a "Folder". This allows one to group Items into subsets that can have their own meaning. An
* ItemGroup also allows one to define a subset of common properties to be applied to each Item within it. For
* example, a `test` event defined on an ItemGroup is executed while testing any Item that belongs to that group.
* Similarly, ItemGroups can have a common {@RequestAuth} defined so that every {@link Request}, when processed,
* requires to be authenticated using the `auth` defined in the group.
*
* Essentially, {@link Collection} too is a special type of ItemGroup ;-).
*
* @constructor
* @extends {Property}
*
* @param {ItemGroup.definition=} [definition] While creating a new instance of ItemGroup, one can provide the
* initial configuration of the item group with the requests it contains, the authentication applied to all
* requests, events that the requests responds to, etc.
*
* @example <caption>Add a new ItemGroup to a collection instance</caption>
* var Collection = require('postman-collection').Collection,
* ItemGroup = require('postman-collection').ItemGroup,
* myCollection;
*
* myCollection = new Collection(); // create an empty collection
* myCollection.items.add(new ItemGroup({ // add a folder called "blank folder"
* "name": "This is a blank folder"
* }));
*/
ItemGroup = function PostmanItemGroup (definition) {
// this constructor is intended to inherit and as such the super constructor is required to be executed
ItemGroup.super_.apply(this, arguments);
_.mergeDefined(this, /** @lends ItemGroup.prototype */ {
/**
* This is a {@link PropertyList} that holds the list of {@link Item}s or {@link ItemGroup}s belonging to a
* {@link Collection} or to an {@link ItemGroup}. Operation on an individual item in this list can be
* performed using various functions available to a {@link PropertyList}.
*
* @type {PropertyList<(Item|ItemGroup)>}
*
* @example <caption>Fetch empty ItemGroups in a list loaded from a file</caption>
* var fs = require('fs'), // needed to read JSON file from disk
* Collection = require('postman-collection').Collection,
* myCollection,
* emptyGroups;
* // Load a collection to memory from a JSON file on disk (say, sample-collection.json)
* myCollection = new Collection(JSON.stringify(fs.readFileSync('sample-collection.json').toString()));
*
* // Filter items in Collection root that is an empty ItemGroup
* emptyGroups = myCollection.items.filter(function (item) {
* return item && item.items && (item.items.count() === 0);
* });
*
* // Log the emptyGroups array to check it's contents
* console.log(emptyGroups);
*/
items: new PropertyList(ItemGroup._createNewGroupOrItem, this, definition && definition.item),
/**
* One can define the default authentication method required for every item that belongs to this list.
* Individual {@link Request}s can override this in their own definitions. More on how to define an
* authentication method is outlined in the {@link RequestAuth} property.
*
* @type {RequestAuth}
*
* @example <caption>Define an entire ItemGroup (folder) or Collection to follow Basic Auth</caption>
* var fs = require('fs'),
* Collection = require('postman-collection').Collection,
* RequestAuth = require('postman-collection').RequestAuth,
* mycollection;
*
* // Create a collection having two requests
* myCollection = new Collection();
* myCollection.items.add([
* { name: 'GET Request', request: 'https://postman-echo.com/get?auth=basic' },
* { name: 'PUT Request', request: 'https://postman-echo.com/put?auth=basic' }
* ]);
*
* // Add basic auth to the Collection, to be applied on all requests.
* myCollection.auth = new RequestAuth({
* type: 'basic',
* username: 'postman',
* password: 'password'
* });
*/
// auth is a special case, empty RequestAuth should not be created for falsy values
// to allow inheritance from parent
auth: definition && definition.auth ? new RequestAuth(definition.auth) : undefined,
/**
* In this list, one can define the {@link Script}s to be executed when an event is triggered. Events are
* triggered before certain actions are taken on a Collection, Request, etc. For example, executing a
* request causes the `prerequest` and the `test` events to be triggered.
*
* @type {EventList}
* @memberOf Collection.prototype
*
* @example <caption>Executing a common test script for all requests in a collection</caption>
* var fs = require('fs'), // needed to read JSON file from disk
* Collection = require('postman-collection').Collection,
* myCollection;
*
* // Load a collection to memory from a JSON file on disk (say, sample-collection.json)
* myCollection = new Collection(JSON.stringify(fs.readFileSync('sample-collection.json').toString()));
*
* // Add an event listener to the collection that listens to the `test` event.
* myCollection.events.add({
* listen: 'test',
* script: {
* exec: 'tests["Status code is 200"] = (responseCode.code === 200)'
* }
* });
*/
events: new EventList(this, definition && definition.event),
/**
* Set of configurations used to alter the usual behavior of sending the request.
*
* @type {Object}
* @property {Boolean} disableBodyPruning Disable body pruning for request methods like GET, HEAD etc.
*/
protocolProfileBehavior: definition && typeof definition.protocolProfileBehavior === OBJECT ?
definition.protocolProfileBehavior : undefined
});
}), Property);
_.assign(ItemGroup.prototype, /** @lends ItemGroup.prototype */ {
/**
* Defines that this property requires an ID field
*
* @private
* @readonly
*/
_postman_propertyRequiresId: true,
/**
* Calls the callback for each item belonging to itself. If any ItemGroups are encountered,
* they will call the callback on their own Items.
*
* @private
* @param {Function} callback -
*/
forEachItem: function forEachItem (callback) {
this.items.each(function (item) {
return ItemGroup.isItemGroup(item) ? item.forEachItem(callback) : callback(item, this);
}, this);
},
/**
* Calls the callback for each itemgroup belonging to itself. All ItemGroups encountered will also,
* call the callback on their own ItemGroups
*
* @private
* @param {Function} callback -
*/
forEachItemGroup: function forEachItemGroup (callback) {
this.items.each(function (item) {
if (ItemGroup.isItemGroup(item)) {
item.forEachItemGroup(callback);
callback(item, this); // eslint-disable-line callback-return
}
}, this);
},
/**
* Finds the first item with the given name or id in the current ItemGroup.
*
* @param {String} idOrName -
*/
oneDeep: function (idOrName) {
if (!_.isString(idOrName)) { return; }
var item;
this.items.each(function (eachItem) {
if (eachItem.id === idOrName || eachItem.name === idOrName) {
item = eachItem;
return false; // we found something, so bail out of the for loop.
}
if (ItemGroup.isItemGroup(eachItem)) {
item = eachItem.oneDeep(idOrName);
return !item; // bail out of the for loop if we found anything
}
});
return item;
},
/**
* Fetches protocol profile behavior for the current ItemGroup
*
* @private
* @returns {Object}
*
* @note This will not inherit protocol profile behaviors from parent,
* use `getProtocolProfileBehaviorResolved` to achieve that behavior.
*/
getProtocolProfileBehavior: Item.prototype.getProtocolProfileBehavior,
/**
* Fetches protocol profile behavior applicable for the current ItemGroup,
* inherited from parent ItemGroups(s).
*
* @private
* @returns {Object}
*/
getProtocolProfileBehaviorResolved: Item.prototype.getProtocolProfileBehaviorResolved,
/**
* Set or update protocol profile behavior for the current ItemGroup.
*
* @example <caption> Set or update protocol profile behavior </caption>
* itemGroup.setProtocolProfileBehavior('strictSSL', false);
*
* @private
* @param {String} key - protocol profile behavior name
* @param {*} value - protocol profile behavior value
* @returns {ItemGroup}
*/
setProtocolProfileBehavior: Item.prototype.setProtocolProfileBehavior,
/**
* Unset or delete protocol profile behavior for the current ItemGroup.
*
* @example <caption> Unset protocol profile behavior </caption>
* itemGroup.unsetProtocolProfileBehavior('strictSSL');
*
* @private
* @param {String} key - protocol profile behavior name to unset
* @returns {ItemGroup}
*/
unsetProtocolProfileBehavior: Item.prototype.unsetProtocolProfileBehavior,
/**
* Sets authentication method for all the items within this group
*
* @param {?String|RequestAuth.definition} type
* @param {VariableList=} [options]
*
* @note This function was previously (in v2 of SDK) used to clone request and populate headers. Now it is used to
* only set auth information to request
*/
authorizeRequestsUsing: Request.prototype.authorizeUsing
});
_.assign(ItemGroup, /** @lends ItemGroup */ {
/**
* Defines the name of this property for internal use.
*
* @private
* @readOnly
* @type {String}
*/
_postman_propertyName: 'ItemGroup',
/**
* Iterator function to update an itemgroup's item array with appropriate objects from definition.
*
* @private
* @this {ItemGroup}
* @param {Object} item - the definition of an item or group
* @returns {ItemGroup|Item}
* @note
* This function is intended to be used in scope of an instance of a {@link ItemGroup).
*/
_createNewGroupOrItem: function (item) {
if (Item.isItem(item) || ItemGroup.isItemGroup(item)) { return item; }
return item && item.item ? new ItemGroup(item) : new Item(item);
},
/**
* Check whether an object is an instance of {@link ItemGroup}.
*
* @param {*} obj -
* @returns {Boolean}
*/
isItemGroup: function (obj) {
return Boolean(obj) && ((obj instanceof ItemGroup) ||
_.inSuperChain(obj.constructor, '_postman_propertyName', ItemGroup._postman_propertyName));
}
});
module.exports = {
ItemGroup
};