@barchart/portfolio-api-common 1.0.161 → 1.0.165

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,17 +48,9 @@ module.exports = (() => {
48
48
  const currentSummaryFrame = PositionSummaryFrame.YTD;
49
49
  const currentSummaryRange = array.last(currentSummaryFrame.getRecentRanges(0));
50
50
 
51
- this._groupBindings = { };
52
-
53
- const addGroupBinding = (group, dispoable) => {
54
- const id = group.id;
55
-
56
- if (!this._groupBindings.hasOwnProperty(id)) {
57
- this._groupBindings[id] = new DisposableStack();
58
- }
51
+ this._definitions = definitions;
59
52
 
60
- this._groupBindings[id].push(dispoable);
61
- };
53
+ this._groupBindings = { };
62
54
 
63
55
  this._portfolios = portfolios.reduce((map, portfolio) => {
64
56
  map[portfolio.portfolio] = portfolio;
@@ -164,132 +156,82 @@ module.exports = (() => {
164
156
  return Rate.fromPair(Decimal.ONE, symbol);
165
157
  });
166
158
 
167
- this._trees = definitions.reduce((map, treeDefinition) => {
159
+ this._trees = this._definitions.reduce((map, treeDefinition) => {
168
160
  const tree = new Tree();
169
161
 
170
- const createGroups = (currentTree, items, levelDefinitions) => {
171
- if (levelDefinitions.length === 0) {
172
- return;
173
- }
174
-
175
- const parent = currentTree.getValue() || null;
176
-
177
- const levelDefinition = levelDefinitions[0];
178
-
179
- const populatedObjects = array.groupBy(items, levelDefinition.keySelector);
180
- const populatedGroups = Object.keys(populatedObjects).reduce((list, key) => {
181
- const items = populatedObjects[key];
182
- const first = items[0];
162
+ createGroups.call(this, tree, tree, this._items, treeDefinition, treeDefinition.definitions);
163
+
164
+ map[treeDefinition.name] = tree;
183
165
 
184
- list.push(new PositionGroup(this, parent, items, levelDefinition.currencySelector(first), key, levelDefinition.descriptionSelector(first), levelDefinition.single && items.length === 1, levelDefinition.aggregateCash));
166
+ return map;
167
+ }, { });
168
+ }
185
169
 
186
- return list;
187
- }, [ ]);
170
+ addPortfolio(portfolio) {
171
+ assert.argumentIsRequired(portfolio, 'portfolio', Object);
172
+ assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
173
+ assert.argumentIsRequired(portfolio.name, 'portfolio.name', String);
188
174
 
189
- const missingGroups = array.difference(levelDefinition.requiredGroups.map(group => group.key), populatedGroups.map(group => group.key))
190
- .map((key) => {
191
- return levelDefinition.requiredGroups.find(g => g.key === key);
192
- });
175
+ const key = portfolio.portfolio;
193
176
 
194
- const empty = missingGroups.map((group) => {
195
- return new PositionGroup(this, parent, [ ], group.currency, group.key, group.description);
196
- });
177
+ if (!this._portfolios.hasOwnProperty(key)) {
178
+ this._portfolios[key] = portfolio;
197
179
 
198
- const compositeGroups = populatedGroups.concat(empty);
180
+ this._definitions.forEach((treeDefinition) => {
181
+ const tree = this._trees[treeDefinition.name];
182
+ const levelDefinitions = treeDefinition.definitions;
199
183
 
200
- let builder;
184
+ let portfolioRequiredGroup = null;
201
185
 
202
- if (levelDefinition.requiredGroups.length !== 0) {
203
- const ordering = levelDefinition.requiredGroups.reduce((map, group, index) => {
204
- map[group.description] = index;
186
+ let portfolioLevelDefinition = null;
187
+ let portfolioLevelDefinitionIndex = null;
205
188
 
206
- return map;
207
- }, { });
189
+ levelDefinitions.forEach((levelDefinition, i) => {
190
+ if (portfolioRequiredGroup === null) {
191
+ portfolioRequiredGroup = levelDefinition.generateRequiredGroup(portfolio);
208
192
 
209
- const getIndex = (description) => {
210
- if (ordering.hasOwnProperty(description)) {
211
- return ordering[description];
212
- } else {
213
- return Number.MAX_VALUE;
193
+ if (portfolioRequiredGroup !== null) {
194
+ portfolioLevelDefinition = levelDefinition;
195
+ portfolioLevelDefinitionIndex = i;
214
196
  }
215
- };
197
+ }
198
+ });
216
199
 
217
- builder = ComparatorBuilder.startWith((a, b) => {
218
- return comparators.compareNumbers(getIndex(a.description), getIndex(b.description));
219
- }).thenBy((a, b) => {
220
- return comparators.compareStrings(a.description, b.description);
221
- });
222
- } else {
223
- builder = ComparatorBuilder.startWith((a, b) => {
224
- return comparators.compareStrings(a.description, b.description);
225
- });
226
- }
200
+ if (portfolioRequiredGroup !== null) {
201
+ let parentTrees = [ ];
227
202
 
228
- compositeGroups.sort(builder.toComparator());
203
+ if (portfolioLevelDefinitionIndex === 0) {
204
+ parentTrees.push(tree);
205
+ } else {
206
+ const parentLevelDefinition = levelDefinitions[ portfolioLevelDefinitionIndex - 1 ];
229
207
 
230
- const initializeGroupObservers = (group, groupTree) => {
231
- addGroupBinding(group, group.registerGroupExcludedChangeHandler((excluded, sender) => {
232
- groupTree.climb((parentGroup) => {
233
- if (parentGroup) {
234
- let excludedItems = [];
208
+ tree.walk((group, groupTree) => {
209
+ if (group.definition === parentLevelDefinition) {
210
+ parentTrees.push(groupTree);
211
+ }
212
+ });
213
+ }
235
214
 
236
- currentTree.walk((childGroup) => {
237
- if (childGroup.excluded) {
238
- excludedItems = excludedItems.concat(childGroup.items);
239
- }
240
- }, false, false);
215
+ const overrideRequiredGroups = [ portfolioRequiredGroup ];
241
216
 
242
- parentGroup.setExcludedItems(array.unique(excludedItems));
243
- }
244
- }, false);
245
-
246
- if (treeDefinition.exclusionDependencies.length > 0) {
247
- const dependantTrees = treeDefinition.exclusionDependencies.reduce((trees, name) => {
248
- if (this._trees.hasOwnProperty(name)) {
249
- trees.push(this._trees[name]);
250
- }
251
-
252
- return trees;
253
- }, [ ]);
254
-
255
- if (dependantTrees.length > 0) {
256
- let excludedItems = [ ];
257
-
258
- tree.walk((childGroup) => {
259
- if (childGroup.excluded) {
260
- excludedItems = excludedItems.concat(childGroup.items);
261
- }
262
- }, false, false);
263
-
264
- dependantTrees.forEach((dependantTrees) => {
265
- dependantTrees.walk((childGroup) => {
266
- childGroup.setExcludedItems(excludedItems);
267
- }, false, false);
268
- });
269
- }
270
- }
271
- }));
272
- };
217
+ parentTrees.forEach((t) => {
218
+ createGroups.call(this, tree, t, [ ], treeDefinition, levelDefinitions.slice(portfolioLevelDefinitionIndex), overrideRequiredGroups);
219
+ });
220
+ }
221
+ });
222
+ }
223
+ }
273
224
 
274
- compositeGroups.forEach((group) => {
275
- const childTree = currentTree.addChild(group);
225
+ removePortfolio(portfolio) {
276
226
 
277
- initializeGroupObservers(group, childTree);
227
+ }
278
228
 
279
- addGroupBinding(group, group.registerMarketPercentChangeHandler(() => {
280
- currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
281
- }));
229
+ mutatePosition(position, summary) {
282
230
 
283
- createGroups(childTree, group.items, array.dropLeft(levelDefinitions));
284
- });
285
- };
231
+ }
286
232
 
287
- createGroups(tree, this._items, treeDefinition.definitions);
288
-
289
- map[treeDefinition.name] = tree;
233
+ removePosition(position) {
290
234
 
291
- return map;
292
- }, { });
293
235
  }
294
236
 
295
237
  /**
@@ -466,6 +408,16 @@ module.exports = (() => {
466
408
  return findNode(this._trees[name], keys).getChildren().map(node => node.getValue());
467
409
  }
468
410
 
411
+ /**
412
+ * Returns all portfolios in the container
413
+ *
414
+ * @public
415
+ * @return {Array.<Object>}
416
+ */
417
+ getPortfolios() {
418
+ return this._portfolios;
419
+ }
420
+
469
421
  /**
470
422
  * Returns all positions for the given portfolio.
471
423
  *
@@ -523,5 +475,134 @@ module.exports = (() => {
523
475
  }
524
476
  }
525
477
 
478
+ function addGroupBinding(group, dispoable) {
479
+ const id = group.id;
480
+
481
+ if (!this._groupBindings.hasOwnProperty(id)) {
482
+ this._groupBindings[id] = new DisposableStack();
483
+ }
484
+
485
+ this._groupBindings[id].push(dispoable);
486
+ }
487
+
488
+ function createGroups(parentTree, currentTree, items, treeDefinition, levelDefinitions, overrideRequiredGroups) {
489
+ if (levelDefinitions.length === 0) {
490
+ return;
491
+ }
492
+
493
+ const parent = currentTree.getValue() || null;
494
+
495
+ const levelDefinition = levelDefinitions[0];
496
+
497
+ const populatedObjects = array.groupBy(items, levelDefinition.keySelector);
498
+ const populatedGroups = Object.keys(populatedObjects).reduce((list, key) => {
499
+ const items = populatedObjects[key];
500
+ const first = items[0];
501
+
502
+ list.push(new PositionGroup(this, parent, levelDefinition, items, levelDefinition.currencySelector(first), key, levelDefinition.descriptionSelector(first), levelDefinition.single && items.length === 1, levelDefinition.aggregateCash));
503
+
504
+ return list;
505
+ }, [ ]);
506
+
507
+ const requiredGroupsToUse = overrideRequiredGroups || levelDefinition.requiredGroups;
508
+
509
+ const missingGroups = array.difference(requiredGroupsToUse.map(group => group.key), populatedGroups.map(group => group.key))
510
+ .map((key) => {
511
+ return requiredGroupsToUse.find(g => g.key === key);
512
+ });
513
+
514
+ const empty = missingGroups.map((group) => {
515
+ return new PositionGroup(this, parent, levelDefinition, [ ], group.currency, group.key, group.description);
516
+ });
517
+
518
+ const compositeGroups = populatedGroups.concat(empty);
519
+
520
+ let builder;
521
+
522
+ if (requiredGroupsToUse.length !== 0) {
523
+ const ordering = requiredGroupsToUse.reduce((map, group, index) => {
524
+ map[group.description] = index;
525
+
526
+ return map;
527
+ }, { });
528
+
529
+ const getIndex = (description) => {
530
+ if (ordering.hasOwnProperty(description)) {
531
+ return ordering[description];
532
+ } else {
533
+ return Number.MAX_VALUE;
534
+ }
535
+ };
536
+
537
+ builder = ComparatorBuilder.startWith((a, b) => {
538
+ return comparators.compareNumbers(getIndex(a.description), getIndex(b.description));
539
+ }).thenBy((a, b) => {
540
+ return comparators.compareStrings(a.description, b.description);
541
+ });
542
+ } else {
543
+ builder = ComparatorBuilder.startWith((a, b) => {
544
+ return comparators.compareStrings(a.description, b.description);
545
+ });
546
+ }
547
+
548
+ compositeGroups.sort(builder.toComparator());
549
+
550
+ const initializeGroupObservers = (group, groupTree) => {
551
+ addGroupBinding.call(this, group, group.registerGroupExcludedChangeHandler((excluded, sender) => {
552
+ groupTree.climb((parentGroup) => {
553
+ if (parentGroup) {
554
+ let excludedItems = [];
555
+
556
+ currentTree.walk((childGroup) => {
557
+ if (childGroup.excluded) {
558
+ excludedItems = excludedItems.concat(childGroup.items);
559
+ }
560
+ }, false, false);
561
+
562
+ parentGroup.setExcludedItems(array.unique(excludedItems));
563
+ }
564
+ }, false);
565
+
566
+ if (treeDefinition.exclusionDependencies.length > 0) {
567
+ const dependantTrees = treeDefinition.exclusionDependencies.reduce((trees, name) => {
568
+ if (this._trees.hasOwnProperty(name)) {
569
+ trees.push(this._trees[name]);
570
+ }
571
+
572
+ return trees;
573
+ }, [ ]);
574
+
575
+ if (dependantTrees.length > 0) {
576
+ let excludedItems = [ ];
577
+
578
+ parentTree.walk((childGroup) => {
579
+ if (childGroup.excluded) {
580
+ excludedItems = excludedItems.concat(childGroup.items);
581
+ }
582
+ }, false, false);
583
+
584
+ dependantTrees.forEach((dependantTrees) => {
585
+ dependantTrees.walk((childGroup) => {
586
+ childGroup.setExcludedItems(excludedItems);
587
+ }, false, false);
588
+ });
589
+ }
590
+ }
591
+ }));
592
+ };
593
+
594
+ compositeGroups.forEach((group) => {
595
+ const childTree = currentTree.addChild(group);
596
+
597
+ initializeGroupObservers(group, childTree);
598
+
599
+ addGroupBinding.call(this, group, group.registerMarketPercentChangeHandler(() => {
600
+ currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
601
+ }));
602
+
603
+ createGroups.call(this, parentTree, childTree, group.items, treeDefinition, array.dropLeft(levelDefinitions));
604
+ });
605
+ }
606
+
526
607
  return PositionContainer;
527
608
  })();
@@ -22,6 +22,7 @@ module.exports = (() => {
22
22
  * @public
23
23
  * @param {PositionContainer} container
24
24
  * @param {PositionGroup|null} parent
25
+ * @param {LevelDefinition} definition
25
26
  * @param {Array.<PositionItem>} items
26
27
  * @param {Currency} currency
27
28
  * @param {String} key
@@ -30,8 +31,10 @@ module.exports = (() => {
30
31
  * @param {Boolean=} aggregateCash
31
32
  */
32
33
  class PositionGroup {
33
- constructor(container, parent, items, currency, key, description, single, aggregateCash) {
34
+ constructor(container, parent, definition, items, currency, key, description, single, aggregateCash) {
34
35
  this._id = counter++;
36
+
37
+ this._definition = definition;
35
38
  this._container = container;
36
39
  this._parent = parent || null;
37
40
 
@@ -209,6 +212,16 @@ module.exports = (() => {
209
212
  return this._id;
210
213
  }
211
214
 
215
+ /**
216
+ * The {@link LevelDefinition} which was used to generate this group.
217
+ *
218
+ * @public
219
+ * @returns {LevelDefinition}
220
+ */
221
+ get definition() {
222
+ return this._definition;
223
+ }
224
+
212
225
  /**
213
226
  * The key of the group.
214
227
  *
@@ -294,6 +307,16 @@ module.exports = (() => {
294
307
  return this._excluded;
295
308
  }
296
309
 
310
+ addItems(items) {
311
+
312
+ this.refresh();
313
+ }
314
+
315
+ removeItems(items) {
316
+
317
+ this.refresh();
318
+ }
319
+
297
320
  /**
298
321
  * Sets the list of items which are excluded from group aggregation calculations.
299
322
  *
@@ -1,6 +1,9 @@
1
1
  const assert = require('@barchart/common-js/lang/assert'),
2
+ Currency = require('@barchart/common-js/lang/Currency'),
2
3
  is = require('@barchart/common-js/lang/is');
3
4
 
5
+ const InstrumentType = require('./../../data/InstrumentType');
6
+
4
7
  module.exports = (() => {
5
8
  'use strict';
6
9
 
@@ -15,12 +18,12 @@ module.exports = (() => {
15
18
  * @param {PositionLevelDefinition~descriptionSelector} descriptionSelector
16
19
  * @param {PositionLevelDefinition~currencySelector} currencySelector
17
20
  * @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
18
- * @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
19
21
  * @param {Boolean=} single
20
22
  * @param {Boolean=} aggregateCash
23
+ * @param {Function=} injectPositions
21
24
  */
22
25
  class PositionLevelDefinition {
23
- constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash) {
26
+ constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash, requiredGroupGenerator) {
24
27
  assert.argumentIsRequired(name, 'name', String);
25
28
  assert.argumentIsRequired(keySelector, 'keySelector', Function);
26
29
  assert.argumentIsRequired(descriptionSelector, 'descriptionSelector', Function);
@@ -32,6 +35,7 @@ module.exports = (() => {
32
35
 
33
36
  assert.argumentIsOptional(single, 'single', Boolean);
34
37
  assert.argumentIsOptional(aggregateCash, 'aggregateCash', Boolean);
38
+ assert.argumentIsOptional(requiredGroupGenerator, 'requiredGroupGenerator', Function);
35
39
 
36
40
  this._name = name;
37
41
 
@@ -40,8 +44,11 @@ module.exports = (() => {
40
44
  this._currencySelector = currencySelector;
41
45
 
42
46
  this._requiredGroups = requiredGroups || [ ];
47
+
43
48
  this._single = is.boolean(single) && single;
44
49
  this._aggregateCash = is.boolean(aggregateCash) && aggregateCash;
50
+
51
+ this._requiredGroupGenerator = requiredGroupGenerator || (input => null);
45
52
  }
46
53
 
47
54
  /**
@@ -118,6 +125,96 @@ module.exports = (() => {
118
125
  return this._aggregateCash;
119
126
  }
120
127
 
128
+ /**
129
+ * Given an input, potentially creates a new {@link PositionLevelDefinition~RequiredGroup}.
130
+ *
131
+ * @public
132
+ * @param {*} input
133
+ * @returns {PositionLevelDefinition~RequiredGroup|null}
134
+ */
135
+ generateRequiredGroup(input) {
136
+ const requiredGroup = this._requiredGroupGenerator(input);
137
+
138
+ if (requiredGroup !== null) {
139
+ this._requiredGroups.push(requiredGroup);
140
+ }
141
+
142
+ return requiredGroup;
143
+ }
144
+
145
+ /**
146
+ * Builds a {@link PositionLevelDefinition~RequiredGroup} for a portfolio.
147
+ *
148
+ * @public
149
+ * @static
150
+ * @param {Object} portfolio
151
+ * @return {PositionLevelDefinition~RequiredGroup}
152
+ */
153
+ static buildRequiredGroupForPortfolio(portfolio) {
154
+ return {
155
+ key: PositionLevelDefinition.getKeyForPortfolioGroup(portfolio),
156
+ description: PositionLevelDefinition.getDescriptionForPortfolioGroup(portfolio),
157
+ currency: Currency.CAD
158
+ };
159
+ }
160
+
161
+ static getKeyForPortfolioGroup(portfolio) {
162
+ assert.argumentIsRequired(portfolio, 'portfolio', Object);
163
+
164
+ return portfolio.portfolio;
165
+ }
166
+
167
+ static getDescriptionForPortfolioGroup(portfolio) {
168
+ assert.argumentIsRequired(portfolio, 'portfolio', Object);
169
+
170
+ return portfolio.name;
171
+ }
172
+
173
+ static getRequiredGroupGeneratorForPortfolio() {
174
+ return (portfolio) => {
175
+ let requiredGroup;
176
+
177
+ if (is.object(portfolio) && is.string(portfolio.portfolio) && is.string(portfolio.name)) {
178
+ requiredGroup = PositionLevelDefinition.buildRequiredGroupForPortfolio(portfolio);
179
+ } else {
180
+ requiredGroup = null;
181
+ }
182
+
183
+ return requiredGroup;
184
+ };
185
+ }
186
+
187
+ /**
188
+ * Builds a {@link PositionLevelDefinition~RequiredGroup} for an asset class.
189
+ *
190
+ * @public
191
+ * @static
192
+ * @param {InstrumentType} type
193
+ * @param {Currency} currency
194
+ * @return {PositionLevelDefinition~RequiredGroup}
195
+ */
196
+ static buildRequiredGroupForAssetClass(type, currency) {
197
+ return {
198
+ key: PositionLevelDefinition.getKeyForAssetClassGroup(type, currency),
199
+ description: PositionLevelDefinition.getDescriptionForAssetClassGroup(type, currency),
200
+ currency: currency
201
+ };
202
+ }
203
+
204
+ static getKeyForAssetClassGroup(type, currency) {
205
+ assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
206
+ assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
207
+
208
+ return `${type.code}|${currency.code}`;
209
+ }
210
+
211
+ static getDescriptionForAssetClassGroup(type, currency) {
212
+ assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
213
+ assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
214
+
215
+ return `${type.alternateDescription}${currency.code === 'CAD' ? '' : ` (${currency.alternateDescription})`}`;
216
+ }
217
+
121
218
  toString() {
122
219
  return '[PositionLevelDefinition]';
123
220
  }
@@ -43,7 +43,7 @@ module.exports = (() => {
43
43
  * bottom-most level of the tree (i.e. leaf nodes).
44
44
  *
45
45
  * @public
46
- * @returns {Array.<PositionTreeDefinition>}
46
+ * @returns {Array.<PositionLevelDefinitions>}
47
47
  */
48
48
  get definitions() {
49
49
  return this._definitions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.0.161",
3
+ "version": "1.0.165",
4
4
  "description": "Common classes used by the Portfolio system",
5
5
  "author": {
6
6
  "name": "Bryan Ingle",
@@ -764,17 +764,9 @@ module.exports = (() => {
764
764
  const currentSummaryFrame = PositionSummaryFrame.YTD;
765
765
  const currentSummaryRange = array.last(currentSummaryFrame.getRecentRanges(0));
766
766
 
767
- this._groupBindings = { };
768
-
769
- const addGroupBinding = (group, dispoable) => {
770
- const id = group.id;
771
-
772
- if (!this._groupBindings.hasOwnProperty(id)) {
773
- this._groupBindings[id] = new DisposableStack();
774
- }
767
+ this._definitions = definitions;
775
768
 
776
- this._groupBindings[id].push(dispoable);
777
- };
769
+ this._groupBindings = { };
778
770
 
779
771
  this._portfolios = portfolios.reduce((map, portfolio) => {
780
772
  map[portfolio.portfolio] = portfolio;
@@ -880,132 +872,82 @@ module.exports = (() => {
880
872
  return Rate.fromPair(Decimal.ONE, symbol);
881
873
  });
882
874
 
883
- this._trees = definitions.reduce((map, treeDefinition) => {
875
+ this._trees = this._definitions.reduce((map, treeDefinition) => {
884
876
  const tree = new Tree();
885
877
 
886
- const createGroups = (currentTree, items, levelDefinitions) => {
887
- if (levelDefinitions.length === 0) {
888
- return;
889
- }
890
-
891
- const parent = currentTree.getValue() || null;
892
-
893
- const levelDefinition = levelDefinitions[0];
894
-
895
- const populatedObjects = array.groupBy(items, levelDefinition.keySelector);
896
- const populatedGroups = Object.keys(populatedObjects).reduce((list, key) => {
897
- const items = populatedObjects[key];
898
- const first = items[0];
878
+ createGroups.call(this, tree, tree, this._items, treeDefinition, treeDefinition.definitions);
879
+
880
+ map[treeDefinition.name] = tree;
899
881
 
900
- list.push(new PositionGroup(this, parent, items, levelDefinition.currencySelector(first), key, levelDefinition.descriptionSelector(first), levelDefinition.single && items.length === 1, levelDefinition.aggregateCash));
882
+ return map;
883
+ }, { });
884
+ }
901
885
 
902
- return list;
903
- }, [ ]);
886
+ addPortfolio(portfolio) {
887
+ assert.argumentIsRequired(portfolio, 'portfolio', Object);
888
+ assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
889
+ assert.argumentIsRequired(portfolio.name, 'portfolio.name', String);
904
890
 
905
- const missingGroups = array.difference(levelDefinition.requiredGroups.map(group => group.key), populatedGroups.map(group => group.key))
906
- .map((key) => {
907
- return levelDefinition.requiredGroups.find(g => g.key === key);
908
- });
891
+ const key = portfolio.portfolio;
909
892
 
910
- const empty = missingGroups.map((group) => {
911
- return new PositionGroup(this, parent, [ ], group.currency, group.key, group.description);
912
- });
893
+ if (!this._portfolios.hasOwnProperty(key)) {
894
+ this._portfolios[key] = portfolio;
913
895
 
914
- const compositeGroups = populatedGroups.concat(empty);
896
+ this._definitions.forEach((treeDefinition) => {
897
+ const tree = this._trees[treeDefinition.name];
898
+ const levelDefinitions = treeDefinition.definitions;
915
899
 
916
- let builder;
900
+ let portfolioRequiredGroup = null;
917
901
 
918
- if (levelDefinition.requiredGroups.length !== 0) {
919
- const ordering = levelDefinition.requiredGroups.reduce((map, group, index) => {
920
- map[group.description] = index;
902
+ let portfolioLevelDefinition = null;
903
+ let portfolioLevelDefinitionIndex = null;
921
904
 
922
- return map;
923
- }, { });
905
+ levelDefinitions.forEach((levelDefinition, i) => {
906
+ if (portfolioRequiredGroup === null) {
907
+ portfolioRequiredGroup = levelDefinition.generateRequiredGroup(portfolio);
924
908
 
925
- const getIndex = (description) => {
926
- if (ordering.hasOwnProperty(description)) {
927
- return ordering[description];
928
- } else {
929
- return Number.MAX_VALUE;
909
+ if (portfolioRequiredGroup !== null) {
910
+ portfolioLevelDefinition = levelDefinition;
911
+ portfolioLevelDefinitionIndex = i;
930
912
  }
931
- };
913
+ }
914
+ });
932
915
 
933
- builder = ComparatorBuilder.startWith((a, b) => {
934
- return comparators.compareNumbers(getIndex(a.description), getIndex(b.description));
935
- }).thenBy((a, b) => {
936
- return comparators.compareStrings(a.description, b.description);
937
- });
938
- } else {
939
- builder = ComparatorBuilder.startWith((a, b) => {
940
- return comparators.compareStrings(a.description, b.description);
941
- });
942
- }
916
+ if (portfolioRequiredGroup !== null) {
917
+ let parentTrees = [ ];
943
918
 
944
- compositeGroups.sort(builder.toComparator());
919
+ if (portfolioLevelDefinitionIndex === 0) {
920
+ parentTrees.push(tree);
921
+ } else {
922
+ const parentLevelDefinition = levelDefinitions[ portfolioLevelDefinitionIndex - 1 ];
945
923
 
946
- const initializeGroupObservers = (group, groupTree) => {
947
- addGroupBinding(group, group.registerGroupExcludedChangeHandler((excluded, sender) => {
948
- groupTree.climb((parentGroup) => {
949
- if (parentGroup) {
950
- let excludedItems = [];
924
+ tree.walk((group, groupTree) => {
925
+ if (group.definition === parentLevelDefinition) {
926
+ parentTrees.push(groupTree);
927
+ }
928
+ });
929
+ }
951
930
 
952
- currentTree.walk((childGroup) => {
953
- if (childGroup.excluded) {
954
- excludedItems = excludedItems.concat(childGroup.items);
955
- }
956
- }, false, false);
931
+ const overrideRequiredGroups = [ portfolioRequiredGroup ];
957
932
 
958
- parentGroup.setExcludedItems(array.unique(excludedItems));
959
- }
960
- }, false);
961
-
962
- if (treeDefinition.exclusionDependencies.length > 0) {
963
- const dependantTrees = treeDefinition.exclusionDependencies.reduce((trees, name) => {
964
- if (this._trees.hasOwnProperty(name)) {
965
- trees.push(this._trees[name]);
966
- }
967
-
968
- return trees;
969
- }, [ ]);
970
-
971
- if (dependantTrees.length > 0) {
972
- let excludedItems = [ ];
973
-
974
- tree.walk((childGroup) => {
975
- if (childGroup.excluded) {
976
- excludedItems = excludedItems.concat(childGroup.items);
977
- }
978
- }, false, false);
979
-
980
- dependantTrees.forEach((dependantTrees) => {
981
- dependantTrees.walk((childGroup) => {
982
- childGroup.setExcludedItems(excludedItems);
983
- }, false, false);
984
- });
985
- }
986
- }
987
- }));
988
- };
933
+ parentTrees.forEach((t) => {
934
+ createGroups.call(this, tree, t, [ ], treeDefinition, levelDefinitions.slice(portfolioLevelDefinitionIndex), overrideRequiredGroups);
935
+ });
936
+ }
937
+ });
938
+ }
939
+ }
989
940
 
990
- compositeGroups.forEach((group) => {
991
- const childTree = currentTree.addChild(group);
941
+ removePortfolio(portfolio) {
992
942
 
993
- initializeGroupObservers(group, childTree);
943
+ }
994
944
 
995
- addGroupBinding(group, group.registerMarketPercentChangeHandler(() => {
996
- currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
997
- }));
945
+ mutatePosition(position, summary) {
998
946
 
999
- createGroups(childTree, group.items, array.dropLeft(levelDefinitions));
1000
- });
1001
- };
947
+ }
1002
948
 
1003
- createGroups(tree, this._items, treeDefinition.definitions);
1004
-
1005
- map[treeDefinition.name] = tree;
949
+ removePosition(position) {
1006
950
 
1007
- return map;
1008
- }, { });
1009
951
  }
1010
952
 
1011
953
  /**
@@ -1182,6 +1124,16 @@ module.exports = (() => {
1182
1124
  return findNode(this._trees[name], keys).getChildren().map(node => node.getValue());
1183
1125
  }
1184
1126
 
1127
+ /**
1128
+ * Returns all portfolios in the container
1129
+ *
1130
+ * @public
1131
+ * @return {Array.<Object>}
1132
+ */
1133
+ getPortfolios() {
1134
+ return this._portfolios;
1135
+ }
1136
+
1185
1137
  /**
1186
1138
  * Returns all positions for the given portfolio.
1187
1139
  *
@@ -1239,6 +1191,135 @@ module.exports = (() => {
1239
1191
  }
1240
1192
  }
1241
1193
 
1194
+ function addGroupBinding(group, dispoable) {
1195
+ const id = group.id;
1196
+
1197
+ if (!this._groupBindings.hasOwnProperty(id)) {
1198
+ this._groupBindings[id] = new DisposableStack();
1199
+ }
1200
+
1201
+ this._groupBindings[id].push(dispoable);
1202
+ }
1203
+
1204
+ function createGroups(parentTree, currentTree, items, treeDefinition, levelDefinitions, overrideRequiredGroups) {
1205
+ if (levelDefinitions.length === 0) {
1206
+ return;
1207
+ }
1208
+
1209
+ const parent = currentTree.getValue() || null;
1210
+
1211
+ const levelDefinition = levelDefinitions[0];
1212
+
1213
+ const populatedObjects = array.groupBy(items, levelDefinition.keySelector);
1214
+ const populatedGroups = Object.keys(populatedObjects).reduce((list, key) => {
1215
+ const items = populatedObjects[key];
1216
+ const first = items[0];
1217
+
1218
+ list.push(new PositionGroup(this, parent, levelDefinition, items, levelDefinition.currencySelector(first), key, levelDefinition.descriptionSelector(first), levelDefinition.single && items.length === 1, levelDefinition.aggregateCash));
1219
+
1220
+ return list;
1221
+ }, [ ]);
1222
+
1223
+ const requiredGroupsToUse = overrideRequiredGroups || levelDefinition.requiredGroups;
1224
+
1225
+ const missingGroups = array.difference(requiredGroupsToUse.map(group => group.key), populatedGroups.map(group => group.key))
1226
+ .map((key) => {
1227
+ return requiredGroupsToUse.find(g => g.key === key);
1228
+ });
1229
+
1230
+ const empty = missingGroups.map((group) => {
1231
+ return new PositionGroup(this, parent, levelDefinition, [ ], group.currency, group.key, group.description);
1232
+ });
1233
+
1234
+ const compositeGroups = populatedGroups.concat(empty);
1235
+
1236
+ let builder;
1237
+
1238
+ if (requiredGroupsToUse.length !== 0) {
1239
+ const ordering = requiredGroupsToUse.reduce((map, group, index) => {
1240
+ map[group.description] = index;
1241
+
1242
+ return map;
1243
+ }, { });
1244
+
1245
+ const getIndex = (description) => {
1246
+ if (ordering.hasOwnProperty(description)) {
1247
+ return ordering[description];
1248
+ } else {
1249
+ return Number.MAX_VALUE;
1250
+ }
1251
+ };
1252
+
1253
+ builder = ComparatorBuilder.startWith((a, b) => {
1254
+ return comparators.compareNumbers(getIndex(a.description), getIndex(b.description));
1255
+ }).thenBy((a, b) => {
1256
+ return comparators.compareStrings(a.description, b.description);
1257
+ });
1258
+ } else {
1259
+ builder = ComparatorBuilder.startWith((a, b) => {
1260
+ return comparators.compareStrings(a.description, b.description);
1261
+ });
1262
+ }
1263
+
1264
+ compositeGroups.sort(builder.toComparator());
1265
+
1266
+ const initializeGroupObservers = (group, groupTree) => {
1267
+ addGroupBinding.call(this, group, group.registerGroupExcludedChangeHandler((excluded, sender) => {
1268
+ groupTree.climb((parentGroup) => {
1269
+ if (parentGroup) {
1270
+ let excludedItems = [];
1271
+
1272
+ currentTree.walk((childGroup) => {
1273
+ if (childGroup.excluded) {
1274
+ excludedItems = excludedItems.concat(childGroup.items);
1275
+ }
1276
+ }, false, false);
1277
+
1278
+ parentGroup.setExcludedItems(array.unique(excludedItems));
1279
+ }
1280
+ }, false);
1281
+
1282
+ if (treeDefinition.exclusionDependencies.length > 0) {
1283
+ const dependantTrees = treeDefinition.exclusionDependencies.reduce((trees, name) => {
1284
+ if (this._trees.hasOwnProperty(name)) {
1285
+ trees.push(this._trees[name]);
1286
+ }
1287
+
1288
+ return trees;
1289
+ }, [ ]);
1290
+
1291
+ if (dependantTrees.length > 0) {
1292
+ let excludedItems = [ ];
1293
+
1294
+ parentTree.walk((childGroup) => {
1295
+ if (childGroup.excluded) {
1296
+ excludedItems = excludedItems.concat(childGroup.items);
1297
+ }
1298
+ }, false, false);
1299
+
1300
+ dependantTrees.forEach((dependantTrees) => {
1301
+ dependantTrees.walk((childGroup) => {
1302
+ childGroup.setExcludedItems(excludedItems);
1303
+ }, false, false);
1304
+ });
1305
+ }
1306
+ }
1307
+ }));
1308
+ };
1309
+
1310
+ compositeGroups.forEach((group) => {
1311
+ const childTree = currentTree.addChild(group);
1312
+
1313
+ initializeGroupObservers(group, childTree);
1314
+
1315
+ addGroupBinding.call(this, group, group.registerMarketPercentChangeHandler(() => {
1316
+ currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
1317
+ }));
1318
+
1319
+ createGroups.call(this, parentTree, childTree, group.items, treeDefinition, array.dropLeft(levelDefinitions));
1320
+ });
1321
+ }
1322
+
1242
1323
  return PositionContainer;
1243
1324
  })();
1244
1325
 
@@ -1267,6 +1348,7 @@ module.exports = (() => {
1267
1348
  * @public
1268
1349
  * @param {PositionContainer} container
1269
1350
  * @param {PositionGroup|null} parent
1351
+ * @param {LevelDefinition} definition
1270
1352
  * @param {Array.<PositionItem>} items
1271
1353
  * @param {Currency} currency
1272
1354
  * @param {String} key
@@ -1275,8 +1357,10 @@ module.exports = (() => {
1275
1357
  * @param {Boolean=} aggregateCash
1276
1358
  */
1277
1359
  class PositionGroup {
1278
- constructor(container, parent, items, currency, key, description, single, aggregateCash) {
1360
+ constructor(container, parent, definition, items, currency, key, description, single, aggregateCash) {
1279
1361
  this._id = counter++;
1362
+
1363
+ this._definition = definition;
1280
1364
  this._container = container;
1281
1365
  this._parent = parent || null;
1282
1366
 
@@ -1454,6 +1538,16 @@ module.exports = (() => {
1454
1538
  return this._id;
1455
1539
  }
1456
1540
 
1541
+ /**
1542
+ * The {@link LevelDefinition} which was used to generate this group.
1543
+ *
1544
+ * @public
1545
+ * @returns {LevelDefinition}
1546
+ */
1547
+ get definition() {
1548
+ return this._definition;
1549
+ }
1550
+
1457
1551
  /**
1458
1552
  * The key of the group.
1459
1553
  *
@@ -1539,6 +1633,16 @@ module.exports = (() => {
1539
1633
  return this._excluded;
1540
1634
  }
1541
1635
 
1636
+ addItems(items) {
1637
+
1638
+ this.refresh();
1639
+ }
1640
+
1641
+ removeItems(items) {
1642
+
1643
+ this.refresh();
1644
+ }
1645
+
1542
1646
  /**
1543
1647
  * Sets the list of items which are excluded from group aggregation calculations.
1544
1648
  *
@@ -2295,8 +2399,11 @@ module.exports = (() => {
2295
2399
 
2296
2400
  },{"./../data/InstrumentType":1,"@barchart/common-js/lang/Currency":14,"@barchart/common-js/lang/Decimal":16,"@barchart/common-js/lang/array":20,"@barchart/common-js/lang/assert":21,"@barchart/common-js/lang/is":23,"@barchart/common-js/messaging/Event":25}],7:[function(require,module,exports){
2297
2401
  const assert = require('@barchart/common-js/lang/assert'),
2402
+ Currency = require('@barchart/common-js/lang/Currency'),
2298
2403
  is = require('@barchart/common-js/lang/is');
2299
2404
 
2405
+ const InstrumentType = require('./../../data/InstrumentType');
2406
+
2300
2407
  module.exports = (() => {
2301
2408
  'use strict';
2302
2409
 
@@ -2311,12 +2418,12 @@ module.exports = (() => {
2311
2418
  * @param {PositionLevelDefinition~descriptionSelector} descriptionSelector
2312
2419
  * @param {PositionLevelDefinition~currencySelector} currencySelector
2313
2420
  * @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
2314
- * @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
2315
2421
  * @param {Boolean=} single
2316
2422
  * @param {Boolean=} aggregateCash
2423
+ * @param {Function=} injectPositions
2317
2424
  */
2318
2425
  class PositionLevelDefinition {
2319
- constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash) {
2426
+ constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash, requiredGroupGenerator) {
2320
2427
  assert.argumentIsRequired(name, 'name', String);
2321
2428
  assert.argumentIsRequired(keySelector, 'keySelector', Function);
2322
2429
  assert.argumentIsRequired(descriptionSelector, 'descriptionSelector', Function);
@@ -2328,6 +2435,7 @@ module.exports = (() => {
2328
2435
 
2329
2436
  assert.argumentIsOptional(single, 'single', Boolean);
2330
2437
  assert.argumentIsOptional(aggregateCash, 'aggregateCash', Boolean);
2438
+ assert.argumentIsOptional(requiredGroupGenerator, 'requiredGroupGenerator', Function);
2331
2439
 
2332
2440
  this._name = name;
2333
2441
 
@@ -2336,8 +2444,11 @@ module.exports = (() => {
2336
2444
  this._currencySelector = currencySelector;
2337
2445
 
2338
2446
  this._requiredGroups = requiredGroups || [ ];
2447
+
2339
2448
  this._single = is.boolean(single) && single;
2340
2449
  this._aggregateCash = is.boolean(aggregateCash) && aggregateCash;
2450
+
2451
+ this._requiredGroupGenerator = requiredGroupGenerator || (input => null);
2341
2452
  }
2342
2453
 
2343
2454
  /**
@@ -2414,6 +2525,96 @@ module.exports = (() => {
2414
2525
  return this._aggregateCash;
2415
2526
  }
2416
2527
 
2528
+ /**
2529
+ * Given an input, potentially creates a new {@link PositionLevelDefinition~RequiredGroup}.
2530
+ *
2531
+ * @public
2532
+ * @param {*} input
2533
+ * @returns {PositionLevelDefinition~RequiredGroup|null}
2534
+ */
2535
+ generateRequiredGroup(input) {
2536
+ const requiredGroup = this._requiredGroupGenerator(input);
2537
+
2538
+ if (requiredGroup !== null) {
2539
+ this._requiredGroups.push(requiredGroup);
2540
+ }
2541
+
2542
+ return requiredGroup;
2543
+ }
2544
+
2545
+ /**
2546
+ * Builds a {@link PositionLevelDefinition~RequiredGroup} for a portfolio.
2547
+ *
2548
+ * @public
2549
+ * @static
2550
+ * @param {Object} portfolio
2551
+ * @return {PositionLevelDefinition~RequiredGroup}
2552
+ */
2553
+ static buildRequiredGroupForPortfolio(portfolio) {
2554
+ return {
2555
+ key: PositionLevelDefinition.getKeyForPortfolioGroup(portfolio),
2556
+ description: PositionLevelDefinition.getDescriptionForPortfolioGroup(portfolio),
2557
+ currency: Currency.CAD
2558
+ };
2559
+ }
2560
+
2561
+ static getKeyForPortfolioGroup(portfolio) {
2562
+ assert.argumentIsRequired(portfolio, 'portfolio', Object);
2563
+
2564
+ return portfolio.portfolio;
2565
+ }
2566
+
2567
+ static getDescriptionForPortfolioGroup(portfolio) {
2568
+ assert.argumentIsRequired(portfolio, 'portfolio', Object);
2569
+
2570
+ return portfolio.name;
2571
+ }
2572
+
2573
+ static getRequiredGroupGeneratorForPortfolio() {
2574
+ return (portfolio) => {
2575
+ let requiredGroup;
2576
+
2577
+ if (is.object(portfolio) && is.string(portfolio.portfolio) && is.string(portfolio.name)) {
2578
+ requiredGroup = PositionLevelDefinition.buildRequiredGroupForPortfolio(portfolio);
2579
+ } else {
2580
+ requiredGroup = null;
2581
+ }
2582
+
2583
+ return requiredGroup;
2584
+ };
2585
+ }
2586
+
2587
+ /**
2588
+ * Builds a {@link PositionLevelDefinition~RequiredGroup} for an asset class.
2589
+ *
2590
+ * @public
2591
+ * @static
2592
+ * @param {InstrumentType} type
2593
+ * @param {Currency} currency
2594
+ * @return {PositionLevelDefinition~RequiredGroup}
2595
+ */
2596
+ static buildRequiredGroupForAssetClass(type, currency) {
2597
+ return {
2598
+ key: PositionLevelDefinition.getKeyForAssetClassGroup(type, currency),
2599
+ description: PositionLevelDefinition.getDescriptionForAssetClassGroup(type, currency),
2600
+ currency: currency
2601
+ };
2602
+ }
2603
+
2604
+ static getKeyForAssetClassGroup(type, currency) {
2605
+ assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
2606
+ assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
2607
+
2608
+ return `${type.code}|${currency.code}`;
2609
+ }
2610
+
2611
+ static getDescriptionForAssetClassGroup(type, currency) {
2612
+ assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
2613
+ assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
2614
+
2615
+ return `${type.alternateDescription}${currency.code === 'CAD' ? '' : ` (${currency.alternateDescription})`}`;
2616
+ }
2617
+
2417
2618
  toString() {
2418
2619
  return '[PositionLevelDefinition]';
2419
2620
  }
@@ -2463,7 +2664,7 @@ module.exports = (() => {
2463
2664
  return PositionLevelDefinition;
2464
2665
  })();
2465
2666
 
2466
- },{"@barchart/common-js/lang/assert":21,"@barchart/common-js/lang/is":23}],8:[function(require,module,exports){
2667
+ },{"./../../data/InstrumentType":1,"@barchart/common-js/lang/Currency":14,"@barchart/common-js/lang/assert":21,"@barchart/common-js/lang/is":23}],8:[function(require,module,exports){
2467
2668
  const assert = require('@barchart/common-js/lang/assert');
2468
2669
 
2469
2670
  const PositionLevelDefinition = require('./PositionLevelDefinition');
@@ -2509,7 +2710,7 @@ module.exports = (() => {
2509
2710
  * bottom-most level of the tree (i.e. leaf nodes).
2510
2711
  *
2511
2712
  * @public
2512
- * @returns {Array.<PositionTreeDefinition>}
2713
+ * @returns {Array.<PositionLevelDefinitions>}
2513
2714
  */
2514
2715
  get definitions() {
2515
2716
  return this._definitions;
@@ -3333,7 +3534,7 @@ module.exports = function () {
3333
3534
  var Currency = function (_Enum) {
3334
3535
  _inherits(Currency, _Enum);
3335
3536
 
3336
- function Currency(code, description, precision, alternateDescription) {
3537
+ function Currency(code, description, precision) {
3337
3538
  _classCallCheck(this, Currency);
3338
3539
 
3339
3540
  var _this = _possibleConstructorReturn(this, (Currency.__proto__ || Object.getPrototypeOf(Currency)).call(this, code, description));
@@ -3341,11 +3542,7 @@ module.exports = function () {
3341
3542
  assert.argumentIsRequired(precision, 'precision', Number);
3342
3543
  assert.argumentIsValid(precision, 'precision', is.integer, 'is an integer');
3343
3544
 
3344
- assert.argumentIsOptional(alternateDescription, 'alternateDescription', String);
3345
-
3346
3545
  _this._precision = precision;
3347
-
3348
- _this._alternateDescription = alternateDescription || description;
3349
3546
  return _this;
3350
3547
  }
3351
3548
 
@@ -3368,19 +3565,6 @@ module.exports = function () {
3368
3565
  return this._precision;
3369
3566
  }
3370
3567
 
3371
- /**
3372
- * An alternate human-readable description.
3373
- *
3374
- * @public
3375
- * @returns {String}
3376
- */
3377
-
3378
- }, {
3379
- key: 'alternateDescription',
3380
- get: function get() {
3381
- return this._alternateDescription;
3382
- }
3383
-
3384
3568
  /**
3385
3569
  * Given a code, returns the enumeration item.
3386
3570
  *
@@ -3438,9 +3622,9 @@ module.exports = function () {
3438
3622
  return Currency;
3439
3623
  }(Enum);
3440
3624
 
3441
- var cad = new Currency('CAD', 'Canadian Dollar', 2, 'CAD$');
3442
- var eur = new Currency('EUR', 'Euro', 2, 'EUR');
3443
- var usd = new Currency('USD', 'US Dollar', 2, 'US$');
3625
+ var cad = new Currency('CAD', 'Canadian Dollar', 2);
3626
+ var eur = new Currency('EUR', 'Euro', 2);
3627
+ var usd = new Currency('USD', 'US Dollar', 2);
3444
3628
 
3445
3629
  return Currency;
3446
3630
  }();
@@ -4414,9 +4598,9 @@ module.exports = function () {
4414
4598
  assert.argumentIsRequired(a, 'a', Decimal, 'Decimal');
4415
4599
  assert.argumentIsRequired(b, 'b', Decimal, 'Decimal');
4416
4600
 
4417
- if (a._big.gt(b._big)) {
4601
+ if (a._big.gt(b)) {
4418
4602
  return 1;
4419
- } else if (a._big.lt(b._big)) {
4603
+ } else if (a._big.lt(b)) {
4420
4604
  return -1;
4421
4605
  } else {
4422
4606
  return 0;
@@ -4877,10 +5061,12 @@ var _createClass = function () { function defineProperties(target, props) { for
4877
5061
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4878
5062
 
4879
5063
  var assert = require('./assert'),
5064
+ is = require('./is'),
4880
5065
  memoize = require('./memoize');
4881
5066
 
4882
5067
  var Currency = require('./Currency'),
4883
- Decimal = require('./Decimal');
5068
+ Decimal = require('./Decimal'),
5069
+ Enum = require('./Enum');
4884
5070
 
4885
5071
  module.exports = function () {
4886
5072
  'use strict';
@@ -5060,7 +5246,12 @@ module.exports = function () {
5060
5246
  assert.argumentIsRequired(amount, 'amount', Decimal, 'Decimal');
5061
5247
  assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
5062
5248
  assert.argumentIsRequired(desiredCurrency, 'desiredCurrency', Currency, 'Currency');
5063
- //assert.argumentIsArray(rates, 'rates', Rate, 'Rate');
5249
+
5250
+ for (var _len = arguments.length, rates = Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
5251
+ rates[_key - 3] = arguments[_key];
5252
+ }
5253
+
5254
+ assert.argumentIsArray(rates, 'rates', Rate, 'Rate');
5064
5255
 
5065
5256
  var converted = void 0;
5066
5257
 
@@ -5070,10 +5261,6 @@ module.exports = function () {
5070
5261
  var numerator = desiredCurrency;
5071
5262
  var denominator = currency;
5072
5263
 
5073
- for (var _len = arguments.length, rates = Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
5074
- rates[_key - 3] = arguments[_key];
5075
- }
5076
-
5077
5264
  var rate = rates.find(function (r) {
5078
5265
  return r.numerator === numerator && r.denominator === denominator || r.numerator === denominator && r.denominator === numerator;
5079
5266
  });
@@ -5124,7 +5311,7 @@ module.exports = function () {
5124
5311
  return Rate;
5125
5312
  }();
5126
5313
 
5127
- },{"./Currency":14,"./Decimal":16,"./assert":21,"./memoize":24}],20:[function(require,module,exports){
5314
+ },{"./Currency":14,"./Decimal":16,"./Enum":18,"./assert":21,"./is":23,"./memoize":24}],20:[function(require,module,exports){
5128
5315
  'use strict';
5129
5316
 
5130
5317
  var assert = require('./assert'),