1 |
|
2 | var winston = require('winston');
|
3 | var name = require('./name');
|
4 | var size = require('../node/size');
|
5 | var bundle = {
|
6 | |
7 |
|
8 |
|
9 |
|
10 |
|
11 | flatten: function(shares, depth){
|
12 |
|
13 |
|
14 | while(bundle.maxDepth(shares) > depth){
|
15 | var min = bundle.min(shares, depth);
|
16 | if(min) {
|
17 | bundle.merge(shares, min);
|
18 | }
|
19 | }
|
20 | },
|
21 | |
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | merge: function(shares, min){
|
34 | var lower = shares[min.lower],
|
35 | upper = shares[min.higher];
|
36 |
|
37 | winston.debug(" flattening "+name.getName(upper)+">"+name.getName(lower));
|
38 |
|
39 | for(var appName in min.diff.bundleToWaste){
|
40 | if( min.diff.bundleToWaste[appName] ){
|
41 | winston.debug(" + "+min.diff[appName]+" "+appName);
|
42 | }
|
43 | }
|
44 |
|
45 |
|
46 | shares.splice(min.higher, 1);
|
47 |
|
48 |
|
49 | lower.nodes = lower.nodes.concat(upper.nodes);
|
50 |
|
51 |
|
52 | var apps = this.appsHash(lower);
|
53 | upper.bundles.forEach(function(appName){
|
54 | if(!apps[appName]){
|
55 | lower.bundles.push(appName);
|
56 | }
|
57 | });
|
58 |
|
59 | },
|
60 | |
61 |
|
62 |
|
63 | maxDepth: function(shares){
|
64 | var packageDepths = {},
|
65 | max = 0;
|
66 | shares.forEach(function(share){
|
67 | share.bundles.forEach(function(appName){
|
68 | packageDepths[appName] = (!packageDepths[appName] ?
|
69 | 1 : packageDepths[appName] +1);
|
70 | max = Math.max(packageDepths[appName], max);
|
71 | });
|
72 | });
|
73 | return max;
|
74 | },
|
75 | |
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 | min: function(shares, depth){
|
91 | var min = {diff: {
|
92 | totalWaste: Infinity,
|
93 | }, lower: 0, higher: 0};
|
94 | for(var i = 0; i < shares.length; i++){
|
95 | var shareA = shares[i];
|
96 | if( shareA.bundles.length == 1 ){
|
97 | continue;
|
98 | }
|
99 | for(var j = i+1; j < shares.length; j++){
|
100 | var shareB = shares[j],
|
101 | diff;
|
102 |
|
103 | var isTooSmall = shareB.bundles.length == 1 &&
|
104 | depth !== 1;
|
105 |
|
106 | if(isTooSmall){
|
107 | continue;
|
108 | }
|
109 |
|
110 | diff = this.diff(shareA, shareB);
|
111 |
|
112 | if(diff.totalWaste < min.diff.totalWaste){
|
113 | min = {
|
114 | diff : diff,
|
115 | lower: i,
|
116 | higher: j
|
117 | };
|
118 | }
|
119 | }
|
120 | }
|
121 | return min.totalWaste === Infinity ? null : min;
|
122 | },
|
123 | |
124 |
|
125 |
|
126 | appsHash : function(shared){
|
127 | var apps = {};
|
128 | shared.bundles.forEach(function(name){
|
129 | apps[name] = true;
|
130 | });
|
131 | return apps;
|
132 | },
|
133 |
|
134 |
|
135 |
|
136 | diff: function(sharedA, sharedB){
|
137 |
|
138 | var nodes = sharedA.nodes.concat(sharedB.nodes),
|
139 |
|
140 | diff = {bundleToWaste: {}, totalWaste: 0};
|
141 |
|
142 |
|
143 | nodes.forEach(function(file){
|
144 | file.bundles.forEach(function(appName){
|
145 | diff.bundleToWaste[appName] = 0;
|
146 | });
|
147 | });
|
148 |
|
149 | for(var appName in diff.bundleToWaste){
|
150 | nodes.forEach(function(node){
|
151 |
|
152 | if(node.bundles.indexOf(appName) == -1){
|
153 | diff.bundleToWaste[appName] += size(node);
|
154 | }
|
155 | });
|
156 | diff.totalWaste += diff.bundleToWaste[appName];
|
157 | }
|
158 | return diff;
|
159 | }
|
160 | };
|
161 |
|
162 | module.exports = function(bundles, depth){
|
163 | bundle.flatten(bundles, depth);
|
164 | };
|