UNPKG

3.94 kBJavaScriptView Raw
1/**
2 * @fileoverview Tracks performance of individual rules.
3 * @author Brandon Mills
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Helpers
10//------------------------------------------------------------------------------
11
12/* istanbul ignore next */
13/**
14 * Align the string to left
15 * @param {string} str string to evaluate
16 * @param {int} len length of the string
17 * @param {string} ch delimiter character
18 * @returns {string} modified string
19 * @private
20 */
21function alignLeft(str, len, ch) {
22 return str + new Array(len - str.length + 1).join(ch || " ");
23}
24
25/* istanbul ignore next */
26/**
27 * Align the string to right
28 * @param {string} str string to evaluate
29 * @param {int} len length of the string
30 * @param {string} ch delimiter character
31 * @returns {string} modified string
32 * @private
33 */
34function alignRight(str, len, ch) {
35 return new Array(len - str.length + 1).join(ch || " ") + str;
36}
37
38//------------------------------------------------------------------------------
39// Module definition
40//------------------------------------------------------------------------------
41
42const enabled = !!process.env.TIMING;
43
44const HEADERS = ["Rule", "Time (ms)", "Relative"];
45const ALIGN = [alignLeft, alignRight, alignRight];
46
47/**
48 * Decide how many rules to show in the output list.
49 * @returns {number} the number of rules to show
50 */
51function getListSize() {
52 const MINIMUM_SIZE = 10;
53
54 if (typeof process.env.TIMING !== "string") {
55 return MINIMUM_SIZE;
56 }
57
58 if (process.env.TIMING.toLowerCase() === "all") {
59 return Number.POSITIVE_INFINITY;
60 }
61
62 const TIMING_ENV_VAR_AS_INTEGER = Number.parseInt(process.env.TIMING, 10);
63
64 return TIMING_ENV_VAR_AS_INTEGER > 10 ? TIMING_ENV_VAR_AS_INTEGER : MINIMUM_SIZE;
65}
66
67/* istanbul ignore next */
68/**
69 * display the data
70 * @param {Object} data Data object to be displayed
71 * @returns {void} prints modified string with console.log
72 * @private
73 */
74function display(data) {
75 let total = 0;
76 const rows = Object.keys(data)
77 .map(key => {
78 const time = data[key];
79
80 total += time;
81 return [key, time];
82 })
83 .sort((a, b) => b[1] - a[1])
84 .slice(0, getListSize());
85
86 rows.forEach(row => {
87 row.push(`${(row[1] * 100 / total).toFixed(1)}%`);
88 row[1] = row[1].toFixed(3);
89 });
90
91 rows.unshift(HEADERS);
92
93 const widths = [];
94
95 rows.forEach(row => {
96 const len = row.length;
97
98 for (let i = 0; i < len; i++) {
99 const n = row[i].length;
100
101 if (!widths[i] || n > widths[i]) {
102 widths[i] = n;
103 }
104 }
105 });
106
107 const table = rows.map(row => (
108 row
109 .map((cell, index) => ALIGN[index](cell, widths[index]))
110 .join(" | ")
111 ));
112
113 table.splice(1, 0, widths.map((width, index) => {
114 const extraAlignment = index !== 0 && index !== widths.length - 1 ? 2 : 1;
115
116 return ALIGN[index](":", width + extraAlignment, "-");
117 }).join("|"));
118
119 console.log(table.join("\n")); // eslint-disable-line no-console
120}
121
122/* istanbul ignore next */
123module.exports = (function() {
124
125 const data = Object.create(null);
126
127 /**
128 * Time the run
129 * @param {*} key key from the data object
130 * @param {Function} fn function to be called
131 * @returns {Function} function to be executed
132 * @private
133 */
134 function time(key, fn) {
135 if (typeof data[key] === "undefined") {
136 data[key] = 0;
137 }
138
139 return function(...args) {
140 let t = process.hrtime();
141
142 fn(...args);
143 t = process.hrtime(t);
144 data[key] += t[0] * 1e3 + t[1] / 1e6;
145 };
146 }
147
148 if (enabled) {
149 process.on("exit", () => {
150 display(data);
151 });
152 }
153
154 return {
155 time,
156 enabled,
157 getListSize
158 };
159
160}());