variable-list.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. "use strict";
  2. var _ = require('../../lodash'), PropertyList = require('./property-list').PropertyList, Property = require('./property').Property, Variable = require('./variable').Variable, VariableList;
  3. _.inherit((
  4. /**
  5. * @constructor
  6. * @extends {PropertyList}
  7. *
  8. * @param {Property} parent
  9. * @param {Object|Array} populate
  10. */
  11. VariableList = function PostmanVariableList(parent, populate) {
  12. // this constructor is intended to inherit and as such the super constructor is required to be executed
  13. VariableList.super_.call(this, Variable, parent, populate);
  14. }), PropertyList);
  15. _.assign(VariableList.prototype, /** @lends VariableList.prototype */ {
  16. /**
  17. * Replaces the variable tokens inside a string with its actual values.
  18. *
  19. * @param {String} str
  20. * @param {Object} [overrides] - additional objects to lookup for variable values
  21. * @returns {String}
  22. */
  23. replace: function (str, overrides) {
  24. return Property.replaceSubstitutions(str, this, overrides);
  25. },
  26. /**
  27. * Recursively replace strings in an object with instances of variables. Note that it clones the original object. If
  28. * the `mutate` param is set to true, then it replaces the same object instead of creating a new one.
  29. *
  30. * @param {Array|Object} obj
  31. * @param {?Array<Object>=} [overrides] - additional objects to lookup for variable values
  32. * @param {Boolean=} [mutate=false]
  33. * @returns {Array|Object}
  34. */
  35. substitute: function (obj, overrides, mutate) {
  36. var resolutionQueue = [], // we use this to store the queue of variable hierarchy
  37. // this is an intermediate object to stimulate a property (makes the do-while loop easier)
  38. variableSource = {
  39. variables: this,
  40. __parent: this.__parent
  41. };
  42. do { // iterate and accumulate as long as you find `.variables` in parent tree
  43. variableSource.variables && resolutionQueue.push(variableSource.variables);
  44. variableSource = variableSource.__parent;
  45. } while (variableSource);
  46. variableSource = null; // cautious cleanup
  47. return Property.replaceSubstitutionsIn(obj, _.union(resolutionQueue, overrides), mutate);
  48. },
  49. /**
  50. * Using this function, one can sync the values of this variable list from a reference object.
  51. *
  52. * @param {Object} obj
  53. * @param {Boolean=} track
  54. * @param {Boolean} [prune=true]
  55. *
  56. * @returns {Object}
  57. */
  58. syncFromObject: function (obj, track, prune) {
  59. var list = this, ops = track && {
  60. created: [],
  61. updated: [],
  62. deleted: []
  63. }, indexer = list._postman_listIndexKey, tmp;
  64. if (!_.isObject(obj)) {
  65. return ops;
  66. }
  67. // ensure that all properties in the object is updated in this list
  68. _.forOwn(obj, function (value, key) {
  69. // we need to create new variable if exists or update existing
  70. if (list.has(key)) {
  71. list.one(key).set(value);
  72. ops && ops.updated.push(key);
  73. }
  74. else {
  75. tmp = { value: value };
  76. tmp[indexer] = key;
  77. list.add(tmp);
  78. tmp = null;
  79. ops && ops.created.push(key);
  80. }
  81. });
  82. // now remove any variable that is not in source object
  83. // @note - using direct `this.reference` list of keys here so that we can mutate the list while iterating
  84. // on it
  85. if (prune !== false) {
  86. _.forEach(list.reference, function (value, key) {
  87. if (obj.hasOwnProperty(key)) {
  88. return;
  89. } // de not delete if source obj has this variable
  90. list.remove(key); // use PropertyList functions to remove so that the .members array is cleared too
  91. ops && ops.deleted.push(key);
  92. });
  93. }
  94. return ops;
  95. },
  96. /**
  97. * Transfer all variables from this list to an object
  98. *
  99. * @param {Object=} [obj]
  100. * @returns {Object}
  101. */
  102. syncToObject: function (obj) {
  103. var list = this;
  104. // in case user did not provide an object to mutate, create a new one
  105. !_.isObject(obj) && (obj = {});
  106. // delete extra variables from object that are not present in list
  107. _.forEach(obj, function (value, key) {
  108. !_.has(list.reference, key) && (delete obj[key]);
  109. });
  110. // we first sync all variables in this list to the object
  111. list.each(function (variable) {
  112. obj[variable.key] = variable.valueOf();
  113. });
  114. return obj;
  115. },
  116. /**
  117. * Fetches a variable and normalize its reference if disabled.
  118. * This updates the disabled variable `reference` in VariableList with its
  119. * last enabled duplicate(if found) in the `members` list.
  120. *
  121. * @private
  122. * @param {String} variableName - The name of the variable to get
  123. * @returns {Variable} - In case of duplicates, returns last enabled
  124. */
  125. oneNormalizedVariable: function (variableName) {
  126. var indexKey = this._postman_listIndexKey, // `key` for Variable
  127. variable = this.reference[variableName], i;
  128. if (variable && !variable.disabled) {
  129. return variable;
  130. }
  131. // traverse the members list in reverse direction in order to find the last enabled
  132. for (i = this.members.length - 1; i >= 0; i--) {
  133. variable = this.members[i];
  134. if (variable[indexKey] === variableName && !variable.disabled) {
  135. // update the input variable reference if comparison is not disabled
  136. this.reference[variableName] = variable;
  137. break; // return updated reference variable
  138. }
  139. }
  140. return this.reference[variableName];
  141. }
  142. });
  143. _.assign(VariableList, /** @lends VariableList */ {
  144. /**
  145. * Defines the name of this property for internal use.
  146. * @private
  147. * @readOnly
  148. * @type {String}
  149. *
  150. * @note that this is directly accessed only in case of VariableList from _.findValue lodash util mixin
  151. */
  152. _postman_propertyName: 'VariableList',
  153. /**
  154. * Checks whether an object is a VariableList
  155. *
  156. * @param {*} obj
  157. * @returns {Boolean}
  158. */
  159. isVariableList: function (obj) {
  160. return Boolean(obj) && ((obj instanceof VariableList) ||
  161. _.inSuperChain(obj.constructor, '_postman_propertyName', VariableList._postman_propertyName));
  162. }
  163. });
  164. module.exports = {
  165. VariableList: VariableList
  166. };