-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathindex.js
112 lines (96 loc) · 3.47 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// extend native
String.prototype.substitute = function (args) { return this.replace(/\{(.*?)\}/g, function (i, match) { return args[match]; }); };
Array.prototype.groupBy = function (prop) { return this.reduce(function (groups, item) { const val = item[prop]; groups[val] = groups[val] || []; groups[val].push(item); return groups }, {}) };
let download = require('./lib/download.js');
let pd = require('./lib/pretty.js').pd;
import hljs from 'highlight.js';
import css from 'highlight.js/lib/languages/javascript';
hljs.registerLanguage('css', css);
let wantZip = true; //zip all css otherwise generate single css download
let coverages = [];
// download all coverage results
Promise.all([
import('./data/coverage_page1.js'),
import('./data/coverage_page2.js'),
]).then((results) => {
// google coverage tool export a json file that contain an object array of coverage results (css/js files)
// merge and group the results for each covered pages
results.forEach((page) => { coverages = coverages.concat(page.default); });
// group coverages for url (file name)
// remove redundant data (full css text content is present in every coverage)
coverages.groupBy('url');
// start
console.clear();
console.log('start cleaning css');
parse_coverge(coverages);
});
function parse_coverge(coverages) {
let rules;
let intervals;
let zip;
if (wantZip) {
zip = new require('./lib/zip.js')();
}
coverages.forEach((source, i) => {
// loop all coverage results (only css files)
let i = 1;
if (source.url.endsWith('.css')) {
// intersection between arrays ranges
rules = '';
intervals = merge_intervals(source.ranges.map(range => [range.start, range.end]));
intervals.forEach((range) => {
rules += source.text.substring(range[0], range[1]);
});
// resolve file name from url
let fileName = source.url.split('\\').pop().split('/').pop();
// prettify css rules
// create direct download or add css in zip
if (wantZip) {
zip.file(fileName, pd.css(rules));
} else {
download(pd.css(rules), fileName, 'text/html');
}
console.log('clean css is ready: ' + source.url);
if(i === 1) { document.getElementById('result').insertAdjacentHTML("afterend", `<p>Removed unused rules with success from: ${fileName}</p>`)};
++i;
}
});
if (wantZip) {
// finally download zip content
zip.generateAsync({ type: "blob" })
.then((content) => {
let name = 'coverages_{t}.zip'.substitute({ t: new Date().getTime() });
download(content, name, 'application/x-zip-compressed');
});
}
console.log('end!');
}
function merge_intervals(ranges) {
/**
* https://gist.github.com/mediaupstream/66293afd101cf4f1970e
*/
if (!ranges.length) return;
// sort ranges based on start time
ranges = ranges.sort((a, b) => {
return a[0] - b[0]
})
// push the first interval onto the stack
var stack = [ranges[0]]
// start from next interval, merge if necessary
for (var i = 1; i < ranges.length; i++) {
// get the top of the stack
var top = stack[stack.length - 1]
// if current interval is not overlapping with the stack top
// push it to the stack
if (top[1] < ranges[i][0]) {
stack.push(ranges[i])
continue;
}
// update end time of previous interval range
// if the current interval end time is larger
if (top[1] < ranges[i][1]) {
stack[stack.length - 1][1] = ranges[i][1]
}
}
return stack;
}