@jsenv/performance-impact 4.1.0 → 4.1.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/performance-impact",
3
- "version": "4.1.0",
3
+ "version": "4.1.2",
4
4
  "description": "Report pull request impacts on performance metrics",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -11,7 +11,7 @@
11
11
  "repository": {
12
12
  "type": "git",
13
13
  "url": "https://github.com/jsenv/workflow",
14
- "directory": "packages/jsenv-performance-impact"
14
+ "directory": "packages/performance-impact"
15
15
  },
16
16
  "engines": {
17
17
  "node": ">=16.13.0"
@@ -36,8 +36,8 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@jsenv/dynamic-import-worker": "1.1.0",
39
- "@jsenv/filesystem": "4.1.6",
40
- "@jsenv/github-pull-request-impact": "1.7.1",
41
- "@jsenv/log": "3.3.2"
39
+ "@jsenv/filesystem": "4.3.2",
40
+ "@jsenv/github-pull-request-impact": "1.7.2",
41
+ "@jsenv/log": "3.4.0"
42
42
  }
43
43
  }
@@ -1,39 +1,39 @@
1
- import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
2
- import { createLogger } from "@jsenv/log"
3
- import { importOneExportFromFile } from "@jsenv/dynamic-import-worker"
1
+ import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem";
2
+ import { createLogger } from "@jsenv/log";
3
+ import { importOneExportFromFile } from "@jsenv/dynamic-import-worker";
4
4
 
5
- import { measureMultipleTimes } from "./internal/measureMultipleTimes.js"
6
- import { assertMetrics } from "./internal/assertions.js"
7
- import { computeMetricsMedian } from "./internal/computeMetricsMedian.js"
8
- import { formatMetricsLog } from "./internal/formatMetricsLog.js"
5
+ import { measureMultipleTimes } from "./internal/measureMultipleTimes.js";
6
+ import { assertMetrics } from "./internal/assertions.js";
7
+ import { computeMetricsMedian } from "./internal/computeMetricsMedian.js";
8
+ import { formatMetricsLog } from "./internal/formatMetricsLog.js";
9
9
 
10
10
  export const importMetricFromFiles = async ({
11
11
  logLevel,
12
12
  directoryUrl,
13
13
  metricsDescriptions,
14
14
  }) => {
15
- const logger = createLogger({ logLevel })
15
+ const logger = createLogger({ logLevel });
16
16
 
17
- directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl)
17
+ directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
18
18
 
19
- const allMetrics = {}
19
+ const allMetrics = {};
20
20
  await Object.keys(metricsDescriptions).reduce(
21
21
  async (previous, metricName) => {
22
- await previous
22
+ await previous;
23
23
 
24
- const metricsDescription = metricsDescriptions[metricName]
24
+ const metricsDescription = metricsDescriptions[metricName];
25
25
  const {
26
26
  file,
27
27
  iterations,
28
28
  msToWaitBetweenEachIteration = 100,
29
- } = metricsDescription
30
- const url = new URL(file, directoryUrl).href
29
+ } = metricsDescription;
30
+ const url = new URL(file, directoryUrl).href;
31
31
 
32
32
  const measure = async () => {
33
- const metrics = await importOneExportFromFile(url)
34
- assertMetrics(metrics, `in ${file}`)
35
- return metrics
36
- }
33
+ const metrics = await importOneExportFromFile(url);
34
+ assertMetrics(metrics, `in ${file}`);
35
+ return metrics;
36
+ };
37
37
 
38
38
  const metricsWithIterations = await measureMultipleTimes(
39
39
  measure,
@@ -41,15 +41,15 @@ export const importMetricFromFiles = async ({
41
41
  {
42
42
  msToWaitBetweenEachIteration,
43
43
  },
44
- )
45
- const metrics = computeMetricsMedian(metricsWithIterations)
44
+ );
45
+ const metrics = computeMetricsMedian(metricsWithIterations);
46
46
 
47
- logger.info(formatMetricsLog(metrics))
47
+ logger.info(formatMetricsLog(metrics));
48
48
 
49
- allMetrics[metricName] = metrics
49
+ allMetrics[metricName] = metrics;
50
50
  },
51
51
  Promise.resolve(),
52
- )
52
+ );
53
53
 
54
- return allMetrics
55
- }
54
+ return allMetrics;
55
+ };
@@ -1,17 +1,17 @@
1
- import { createDetailedMessage } from "@jsenv/log"
1
+ import { createDetailedMessage } from "@jsenv/log";
2
2
 
3
3
  export const assertPerformanceReport = (performanceReport) => {
4
4
  if (typeof performanceReport !== "object" || performanceReport === null) {
5
5
  throw new TypeError(
6
6
  `performanceReport must be an object, received ${performanceReport}.`,
7
- )
7
+ );
8
8
  }
9
9
 
10
10
  Object.keys(performanceReport).forEach((groupName) => {
11
- const metrics = performanceReport[groupName]
12
- assertMetrics(metrics)
13
- })
14
- }
11
+ const metrics = performanceReport[groupName];
12
+ assertMetrics(metrics);
13
+ });
14
+ };
15
15
 
16
16
  export const assertMetrics = (metrics, metricsTrace) => {
17
17
  if (typeof metrics !== "object" || metrics === null) {
@@ -19,29 +19,29 @@ export const assertMetrics = (metrics, metricsTrace) => {
19
19
  createDetailedMessage(`metrics must be an object, got ${metrics}`, {
20
20
  "metrics trace": metricsTrace,
21
21
  }),
22
- )
22
+ );
23
23
  }
24
24
 
25
25
  Object.keys(metrics).forEach((metricName) => {
26
- const metric = metrics[metricName]
26
+ const metric = metrics[metricName];
27
27
  if (typeof metric !== "object") {
28
28
  throw new TypeError(
29
29
  `metric must be an object, got ${metric} for ${metricName}`,
30
- )
30
+ );
31
31
  }
32
32
 
33
- const { value } = metric
33
+ const { value } = metric;
34
34
  if (typeof value !== "number") {
35
35
  throw new TypeError(
36
36
  `metric value must be a number, got ${value} for ${metricName}`,
37
- )
37
+ );
38
38
  }
39
39
 
40
- const { unit } = metric
40
+ const { unit } = metric;
41
41
  if (unit !== undefined && unit !== "ms" && unit !== "byte") {
42
42
  throw new TypeError(
43
43
  `metric type must be undefined, "ms", or "byte", got ${unit} for ${metricName}`,
44
- )
44
+ );
45
45
  }
46
- })
47
- }
46
+ });
47
+ };
@@ -1,4 +1,4 @@
1
- import { renderGroupImpactTable } from "./renderGroupImpactTable.js"
1
+ import { renderGroupImpactTable } from "./renderGroupImpactTable.js";
2
2
 
3
3
  export const createPerfImpactComment = ({
4
4
  pullRequestBase,
@@ -9,47 +9,47 @@ export const createPerfImpactComment = ({
9
9
  formatGroupSummary,
10
10
  formatPerformanceImpactCell,
11
11
  }) => {
12
- const warnings = []
12
+ const warnings = [];
13
13
 
14
14
  // here we have are sure beforeMergeData and afterMergeData are valid
15
15
  // because we assert their shape is correct in reportPerformanceImpact.js#collectInfo()
16
16
  // for metrics here before merge but are no longer in afetr merge, we will ignore them
17
17
  // for new metrics we'll show them without doing the diff
18
18
 
19
- const beforeMergeGroups = beforeMergeData
20
- const afterMergeGroups = afterMergeData
19
+ const beforeMergeGroups = beforeMergeData;
20
+ const afterMergeGroups = afterMergeData;
21
21
 
22
- const groupNames = Object.keys(afterMergeGroups)
22
+ const groupNames = Object.keys(afterMergeGroups);
23
23
  const metricCount = groupNames.reduce((previous, groupName) => {
24
- const afterMergeMetrics = afterMergeGroups[groupName]
25
- return previous + Object.keys(afterMergeMetrics).length
26
- }, 0)
24
+ const afterMergeMetrics = afterMergeGroups[groupName];
25
+ return previous + Object.keys(afterMergeMetrics).length;
26
+ }, 0);
27
27
 
28
28
  if (metricCount === 0) {
29
29
  const body = `<h4 id="perf-impact">Performance impact</h4>
30
30
 
31
- <p>No impact to compute when merging <em>${pullRequestHead}</em> into <em>${pullRequestBase}</em>: there is no performance metric.</p>`
31
+ <p>No impact to compute when merging <em>${pullRequestHead}</em> into <em>${pullRequestBase}</em>: there is no performance metric.</p>`;
32
32
 
33
- return { warnings, body }
33
+ return { warnings, body };
34
34
  }
35
35
 
36
- const groups = []
36
+ const groups = [];
37
37
  groupNames.forEach((groupName) => {
38
- const afterMergeMetrics = afterMergeGroups[groupName]
39
- const afterMergeMetricCount = Object.keys(afterMergeMetrics).length
38
+ const afterMergeMetrics = afterMergeGroups[groupName];
39
+ const afterMergeMetricCount = Object.keys(afterMergeMetrics).length;
40
40
  if (afterMergeMetricCount === 0) {
41
41
  // skip empty groups
42
- return
42
+ return;
43
43
  }
44
44
 
45
- const beforeMergeMetrics = beforeMergeGroups[groupName]
45
+ const beforeMergeMetrics = beforeMergeGroups[groupName];
46
46
  const bigImpacts = beforeMergeMetrics
47
47
  ? getBigImpacts({
48
48
  afterMergeMetrics,
49
49
  beforeMergeMetrics,
50
50
  isPerformanceImpactBig,
51
51
  })
52
- : {}
52
+ : {};
53
53
 
54
54
  groups.push(
55
55
  renderDetails({
@@ -66,38 +66,38 @@ export const createPerfImpactComment = ({
66
66
  bigImpacts,
67
67
  }),
68
68
  }),
69
- )
70
- })
69
+ );
70
+ });
71
71
 
72
72
  const body = `<h4 id="perf-impact">Performance impact</h4>
73
73
 
74
- <p>Impact on ${metricCount} metrics when merging <em>${pullRequestHead}</em> into <em>${pullRequestBase}</em>. Before drawing conclusion, keep in mind <a href="https://github.com/jsenv/workflow/tree/main/packages/jsenv-performance-impact#performance-variability">performance variability</a>.</p>
74
+ <p>Impact on ${metricCount} metrics when merging <em>${pullRequestHead}</em> into <em>${pullRequestBase}</em>. Before drawing conclusion, keep in mind <a href="https://github.com/jsenv/workflow/tree/main/packages/performance-impact#performance-variability">performance variability</a>.</p>
75
75
 
76
76
  ${groups.join(`
77
77
 
78
- `)}`
78
+ `)}`;
79
79
 
80
- return { warnings, body }
81
- }
80
+ return { warnings, body };
81
+ };
82
82
 
83
83
  const getBigImpacts = ({
84
84
  afterMergeMetrics,
85
85
  beforeMergeMetrics,
86
86
  isPerformanceImpactBig,
87
87
  }) => {
88
- const bigImpacts = {}
88
+ const bigImpacts = {};
89
89
 
90
90
  Object.keys(afterMergeMetrics).forEach((metricName) => {
91
- const metricBeforeMerge = beforeMergeMetrics[metricName]
91
+ const metricBeforeMerge = beforeMergeMetrics[metricName];
92
92
  if (metricBeforeMerge === undefined) {
93
- return
93
+ return;
94
94
  }
95
95
 
96
- const metricAfterMerge = afterMergeMetrics[metricName]
97
- const metricUnit = metricAfterMerge.unit
98
- const metricValueAfterMerge = metricAfterMerge.value
99
- const metricValueBeforeMerge = metricBeforeMerge.value
100
- const metricValueDelta = metricValueAfterMerge - metricValueBeforeMerge
96
+ const metricAfterMerge = afterMergeMetrics[metricName];
97
+ const metricUnit = metricAfterMerge.unit;
98
+ const metricValueAfterMerge = metricAfterMerge.value;
99
+ const metricValueBeforeMerge = metricBeforeMerge.value;
100
+ const metricValueDelta = metricValueAfterMerge - metricValueBeforeMerge;
101
101
  if (
102
102
  !isPerformanceImpactBig({
103
103
  metricName,
@@ -107,22 +107,22 @@ const getBigImpacts = ({
107
107
  metricValueDelta,
108
108
  })
109
109
  ) {
110
- return
110
+ return;
111
111
  }
112
112
 
113
113
  bigImpacts[metricName] = {
114
114
  metricValueAfterMerge,
115
115
  metricValueBeforeMerge,
116
116
  metricValueDelta,
117
- }
118
- })
117
+ };
118
+ });
119
119
 
120
- return bigImpacts
121
- }
120
+ return bigImpacts;
121
+ };
122
122
 
123
123
  const renderDetails = ({ summary, content, opened = false, indent = 0 }) => {
124
124
  return `${" ".repeat(indent)}<details${opened ? " open" : ""}>
125
125
  ${" ".repeat(indent + 2)}<summary>${summary}</summary>
126
126
  ${" ".repeat(indent + 2)}${content}
127
- ${" ".repeat(indent)}</details>`
128
- }
127
+ ${" ".repeat(indent)}</details>`;
128
+ };
@@ -1,35 +1,35 @@
1
- import { formatMetricValue } from "../formatMetricValue.js"
2
- import { formatRatioAsPercentage } from "../formatRatio.js"
1
+ import { formatMetricValue } from "../formatMetricValue.js";
2
+ import { formatRatioAsPercentage } from "../formatRatio.js";
3
3
 
4
4
  export const formatImpact = ({
5
5
  metricValueBeforeMerge,
6
6
  metricValueAfterMerge,
7
7
  metricUnit,
8
8
  }) => {
9
- const diff = metricValueAfterMerge - metricValueBeforeMerge
9
+ const diff = metricValueAfterMerge - metricValueBeforeMerge;
10
10
 
11
11
  if (diff === 0) {
12
- return ``
12
+ return ``;
13
13
  }
14
14
 
15
15
  const diffFormatted = `${diff < 0 ? "-" : "+"}${formatMetricValue({
16
16
  value: Math.abs(diff),
17
17
  unit: metricUnit,
18
- })}`
18
+ })}`;
19
19
 
20
- return diffFormatted
21
- }
20
+ return diffFormatted;
21
+ };
22
22
 
23
23
  export const formatImpactAsPercentage = ({
24
24
  metricValueBeforeMerge,
25
25
  metricValueAfterMerge,
26
26
  }) => {
27
- const diff = metricValueAfterMerge - metricValueBeforeMerge
27
+ const diff = metricValueAfterMerge - metricValueBeforeMerge;
28
28
  const diffRatio =
29
29
  metricValueBeforeMerge === 0
30
30
  ? 1
31
31
  : metricValueAfterMerge === 0
32
32
  ? -1
33
- : diff / metricValueBeforeMerge
34
- return formatRatioAsPercentage(diffRatio)
35
- }
33
+ : diff / metricValueBeforeMerge;
34
+ return formatRatioAsPercentage(diffRatio);
35
+ };
@@ -1,9 +1,9 @@
1
- import { jsenvIsPerformanceImpactBig } from "./jsenvIsPerformanceImpactBig.js"
2
- import { jsenvFormatGroupSummary } from "./jsenvFormatGroupSummary.js"
3
- import { jsenvFormatPerformanceImpactCell } from "./jsenvFormatPerformanceImpactCell.js"
1
+ import { jsenvIsPerformanceImpactBig } from "./jsenvIsPerformanceImpactBig.js";
2
+ import { jsenvFormatGroupSummary } from "./jsenvFormatGroupSummary.js";
3
+ import { jsenvFormatPerformanceImpactCell } from "./jsenvFormatPerformanceImpactCell.js";
4
4
 
5
5
  export const jsenvCommentParameters = {
6
6
  isPerformanceImpactBig: jsenvIsPerformanceImpactBig,
7
7
  formatGroupSummary: jsenvFormatGroupSummary,
8
8
  formatPerformanceImpactCell: jsenvFormatPerformanceImpactCell,
9
- }
9
+ };
@@ -1,4 +1,4 @@
1
- import { formatRatioAsPercentage } from "../formatRatio.js"
1
+ import { formatRatioAsPercentage } from "../formatRatio.js";
2
2
 
3
3
  export const jsenvFormatGroupSummary = ({
4
4
  groupName,
@@ -6,38 +6,38 @@ export const jsenvFormatGroupSummary = ({
6
6
  afterMergeMetrics,
7
7
  }) => {
8
8
  if (!beforeMergeMetrics) {
9
- return `${groupName} (new)`
9
+ return `${groupName} (new)`;
10
10
  }
11
11
 
12
12
  const allRatios = getAllImpactRatios({
13
13
  beforeMergeMetrics,
14
14
  afterMergeMetrics,
15
- })
16
- const ratiosCount = allRatios.length
15
+ });
16
+ const ratiosCount = allRatios.length;
17
17
  if (ratiosCount === 0) {
18
- return `${groupName} (no impact)`
18
+ return `${groupName} (no impact)`;
19
19
  }
20
20
 
21
- const ratioSum = allRatios.reduce((previous, ratio) => previous + ratio, 0)
21
+ const ratioSum = allRatios.reduce((previous, ratio) => previous + ratio, 0);
22
22
  if (ratioSum === 0) {
23
- return `${groupName} (no impact)`
23
+ return `${groupName} (no impact)`;
24
24
  }
25
25
 
26
- return `${groupName} (${formatRatioAsPercentage(ratioSum / ratiosCount)})`
27
- }
26
+ return `${groupName} (${formatRatioAsPercentage(ratioSum / ratiosCount)})`;
27
+ };
28
28
 
29
29
  const getAllImpactRatios = ({ afterMergeMetrics, beforeMergeMetrics }) => {
30
- let allRatios = []
30
+ let allRatios = [];
31
31
  Object.keys(afterMergeMetrics).forEach((metricName) => {
32
- const metricBeforeMerge = beforeMergeMetrics[metricName]
32
+ const metricBeforeMerge = beforeMergeMetrics[metricName];
33
33
  if (!metricBeforeMerge) {
34
34
  // it's new, let's ignore
35
- return
35
+ return;
36
36
  }
37
- const metricAfterMerge = afterMergeMetrics[metricName]
38
- const metricValueBeforeMerge = metricBeforeMerge.value
39
- const metricValueAfterMerge = metricAfterMerge.value
40
- const metricDiff = metricValueAfterMerge - metricValueBeforeMerge
37
+ const metricAfterMerge = afterMergeMetrics[metricName];
38
+ const metricValueBeforeMerge = metricBeforeMerge.value;
39
+ const metricValueAfterMerge = metricAfterMerge.value;
40
+ const metricDiff = metricValueAfterMerge - metricValueBeforeMerge;
41
41
  if (
42
42
  metricDiff === 0 &&
43
43
  metricValueAfterMerge === 0 &&
@@ -45,7 +45,7 @@ const getAllImpactRatios = ({ afterMergeMetrics, beforeMergeMetrics }) => {
45
45
  ) {
46
46
  // there is no impact on a metric that is 0
47
47
  // we can ignore this metric
48
- return
48
+ return;
49
49
  }
50
50
 
51
51
  const metricDiffRatio =
@@ -55,8 +55,8 @@ const getAllImpactRatios = ({ afterMergeMetrics, beforeMergeMetrics }) => {
55
55
  ? 1
56
56
  : metricValueAfterMerge === 0
57
57
  ? -1
58
- : metricDiff / metricValueBeforeMerge
59
- allRatios.push(metricDiffRatio)
60
- })
61
- return allRatios
62
- }
58
+ : metricDiff / metricValueBeforeMerge;
59
+ allRatios.push(metricDiffRatio);
60
+ });
61
+ return allRatios;
62
+ };
@@ -1,4 +1,4 @@
1
- import { formatImpact, formatImpactAsPercentage } from "./formatImpact.js"
1
+ import { formatImpact, formatImpactAsPercentage } from "./formatImpact.js";
2
2
 
3
3
  export const jsenvFormatPerformanceImpactCell = ({
4
4
  metricUnit,
@@ -7,23 +7,23 @@ export const jsenvFormatPerformanceImpactCell = ({
7
7
  }) => {
8
8
  // metric is new
9
9
  if (metricValueBeforeMerge === undefined) {
10
- return ``
10
+ return ``;
11
11
  }
12
12
 
13
- const diff = metricValueAfterMerge - metricValueBeforeMerge
13
+ const diff = metricValueAfterMerge - metricValueBeforeMerge;
14
14
  if (diff === 0) {
15
- return ``
15
+ return ``;
16
16
  }
17
17
 
18
18
  const diffFormatted = formatImpact({
19
19
  metricUnit,
20
20
  metricValueAfterMerge,
21
21
  metricValueBeforeMerge,
22
- })
22
+ });
23
23
  const diffAsPercentageFormatted = formatImpactAsPercentage({
24
24
  metricUnit,
25
25
  metricValueBeforeMerge,
26
26
  metricValueAfterMerge,
27
- })
28
- return `${diffFormatted} / ${diffAsPercentageFormatted}`
29
- }
27
+ });
28
+ return `${diffFormatted} / ${diffAsPercentageFormatted}`;
29
+ };
@@ -2,14 +2,14 @@ export const jsenvIsPerformanceImpactBig = ({
2
2
  metricValueBeforeMerge,
3
3
  metricValueDelta,
4
4
  }) => {
5
- const absoluteDelta = Math.abs(metricValueDelta)
5
+ const absoluteDelta = Math.abs(metricValueDelta);
6
6
  const absoluteDeltaAsRatio =
7
- absoluteDelta === 0 ? 0 : absoluteDelta / metricValueBeforeMerge
8
- const absoluteDeltaAsPercentage = absoluteDeltaAsRatio * 100
7
+ absoluteDelta === 0 ? 0 : absoluteDelta / metricValueBeforeMerge;
8
+ const absoluteDeltaAsPercentage = absoluteDeltaAsRatio * 100;
9
9
 
10
10
  // absolute diff as percentage is below 5% -> not big
11
11
  if (absoluteDeltaAsPercentage < 5) {
12
- return false
12
+ return false;
13
13
  }
14
- return true
15
- }
14
+ return true;
15
+ };
@@ -1,7 +1,7 @@
1
- import { formatMetricValue } from "../formatMetricValue.js"
1
+ import { formatMetricValue } from "../formatMetricValue.js";
2
2
 
3
- const METRIC_NAME_MAX_LENGTH = 50
4
- const MAX_METRIC_PER_GROUP = 20
3
+ const METRIC_NAME_MAX_LENGTH = 50;
4
+ const MAX_METRIC_PER_GROUP = 20;
5
5
 
6
6
  export const renderGroupImpactTable = ({
7
7
  formatPerformanceImpactCell,
@@ -26,8 +26,8 @@ export const renderGroupImpactTable = ({
26
26
  bigImpacts,
27
27
  })}
28
28
  </tbody>
29
- </table>`
30
- }
29
+ </table>`;
30
+ };
31
31
 
32
32
  const renderPerfImpactTableBody = ({
33
33
  formatPerformanceImpactCell,
@@ -35,21 +35,21 @@ const renderPerfImpactTableBody = ({
35
35
  afterMergeMetrics,
36
36
  bigImpacts,
37
37
  }) => {
38
- const lines = []
39
- const metricAllNames = Object.keys(afterMergeMetrics)
40
- const metricCount = metricAllNames.length
38
+ const lines = [];
39
+ const metricAllNames = Object.keys(afterMergeMetrics);
40
+ const metricCount = metricAllNames.length;
41
41
  const metricNames =
42
42
  metricCount > MAX_METRIC_PER_GROUP
43
43
  ? metricAllNames.slice(0, MAX_METRIC_PER_GROUP)
44
- : metricAllNames
44
+ : metricAllNames;
45
45
 
46
46
  metricNames.forEach((metricName) => {
47
- const metricNameDisplayed = truncateMetricName(metricName)
48
- const metric = afterMergeMetrics[metricName]
49
- const metricValueAfterMerge = metric.value
47
+ const metricNameDisplayed = truncateMetricName(metricName);
48
+ const metric = afterMergeMetrics[metricName];
49
+ const metricValueAfterMerge = metric.value;
50
50
  const metricBeforeMerge = beforeMergeMetrics
51
51
  ? beforeMergeMetrics[metricName]
52
- : undefined
52
+ : undefined;
53
53
  if (!metricBeforeMerge) {
54
54
  lines.push([
55
55
  `<td nowrap>${metricNameDisplayed}</td>`,
@@ -62,12 +62,12 @@ const renderPerfImpactTableBody = ({
62
62
  isBig: false,
63
63
  })}</td>`,
64
64
  `<td>:baby:</td>`,
65
- ])
66
- return
65
+ ]);
66
+ return;
67
67
  }
68
68
 
69
- const isBig = Boolean(bigImpacts[metricName])
70
- const metricValueBeforeMerge = metricBeforeMerge.value
69
+ const isBig = Boolean(bigImpacts[metricName]);
70
+ const metricValueBeforeMerge = metricBeforeMerge.value;
71
71
  lines.push([
72
72
  `<td nowrap>${metricNameDisplayed}</td>`,
73
73
  `<td nowrap>${formatMetricValue(metricBeforeMerge)}</td>`,
@@ -82,50 +82,50 @@ const renderPerfImpactTableBody = ({
82
82
  metricValueAfterMerge,
83
83
  metricValueBeforeMerge,
84
84
  })}</td>`,
85
- ])
86
- })
85
+ ]);
86
+ });
87
87
  if (metricNames !== metricAllNames) {
88
88
  lines.push([
89
89
  `<td colspan="5" align="center">... ${
90
90
  metricCount - MAX_METRIC_PER_GROUP
91
91
  } more ...</td>`,
92
- ])
92
+ ]);
93
93
  }
94
94
 
95
- return renderTableLines(lines)
96
- }
95
+ return renderTableLines(lines);
96
+ };
97
97
 
98
98
  const renderEmojiCellContent = ({
99
99
  metricValueAfterMerge,
100
100
  metricValueBeforeMerge,
101
101
  }) => {
102
- const delta = metricValueAfterMerge - metricValueBeforeMerge
102
+ const delta = metricValueAfterMerge - metricValueBeforeMerge;
103
103
  if (delta === 0) {
104
- return ":ghost:"
104
+ return ":ghost:";
105
105
  }
106
106
 
107
107
  if (delta > 0) {
108
- return ":arrow_upper_right:"
108
+ return ":arrow_upper_right:";
109
109
  }
110
110
 
111
- return ":arrow_lower_right:"
112
- }
111
+ return ":arrow_lower_right:";
112
+ };
113
113
 
114
114
  const truncateMetricName = (metricName) => {
115
- const length = metricName.length
115
+ const length = metricName.length;
116
116
  if (length > METRIC_NAME_MAX_LENGTH) {
117
- return `${metricName.slice(0, METRIC_NAME_MAX_LENGTH - `…`.length)}…`
117
+ return `${metricName.slice(0, METRIC_NAME_MAX_LENGTH - `…`.length)}…`;
118
118
  }
119
- return metricName
120
- }
119
+ return metricName;
120
+ };
121
121
 
122
122
  const renderTableLines = (lines, { indentCount = 3, indentSize = 2 } = {}) => {
123
123
  if (lines.length === 0) {
124
- return ""
124
+ return "";
125
125
  }
126
126
 
127
- const cellLeftSpacing = indent(indentCount + 1, indentSize)
128
- const lineLeftSpacing = indent(indentCount, indentSize)
127
+ const cellLeftSpacing = indent(indentCount + 1, indentSize);
128
+ const lineLeftSpacing = indent(indentCount, indentSize);
129
129
 
130
130
  return `<tr>${lines.map(
131
131
  (cells) => `
@@ -134,7 +134,7 @@ ${cellLeftSpacing}`)}`,
134
134
  ).join(`
135
135
  ${lineLeftSpacing}</tr>
136
136
  ${lineLeftSpacing}<tr>`)}
137
- ${lineLeftSpacing}</tr>`
138
- }
137
+ ${lineLeftSpacing}</tr>`;
138
+ };
139
139
 
140
- const indent = (count, size) => ` `.repeat(size * count)
140
+ const indent = (count, size) => ` `.repeat(size * count);
@@ -1,15 +1,15 @@
1
- import { median } from "./median.js"
1
+ import { median } from "./median.js";
2
2
 
3
3
  export const computeMetricsMedian = (metrics) => {
4
- const metricsMedian = {}
4
+ const metricsMedian = {};
5
5
 
6
6
  Object.keys(metrics).forEach((metricName) => {
7
- const metricWithIteration = metrics[metricName]
7
+ const metricWithIteration = metrics[metricName];
8
8
  metricsMedian[metricName] = {
9
9
  value: median(metricWithIteration.values),
10
10
  unit: metricWithIteration.unit,
11
- }
12
- })
11
+ };
12
+ });
13
13
 
14
- return metricsMedian
15
- }
14
+ return metricsMedian;
15
+ };
@@ -1,11 +1,11 @@
1
- import { byteAsFileSize, msAsDuration } from "@jsenv/log"
1
+ import { byteAsFileSize, msAsDuration } from "@jsenv/log";
2
2
 
3
3
  export const formatMetricValue = ({ value, unit }) => {
4
- return formatters[unit](value)
5
- }
4
+ return formatters[unit](value);
5
+ };
6
6
 
7
7
  const formatters = {
8
8
  ms: msAsDuration,
9
9
  byte: byteAsFileSize,
10
10
  undefined: (value) => value,
11
- }
11
+ };
@@ -1,9 +1,9 @@
1
- import { formatMetricValue } from "./formatMetricValue.js"
1
+ import { formatMetricValue } from "./formatMetricValue.js";
2
2
 
3
3
  export const formatMetricsLog = (metrics) => {
4
- const metricsReadable = {}
4
+ const metricsReadable = {};
5
5
  Object.keys(metrics).forEach((metricName) => {
6
- metricsReadable[metricName] = formatMetricValue(metrics[metricName])
7
- })
8
- return JSON.stringify(metricsReadable, null, " ")
9
- }
6
+ metricsReadable[metricName] = formatMetricValue(metrics[metricName]);
7
+ });
8
+ return JSON.stringify(metricsReadable, null, " ");
9
+ };
@@ -1,12 +1,12 @@
1
- import { setRoundedPrecision } from "@jsenv/log"
1
+ import { setRoundedPrecision } from "@jsenv/log";
2
2
 
3
3
  export const formatRatioAsPercentage = (ratio) => {
4
- const percentage = ratio * 100
4
+ const percentage = ratio * 100;
5
5
  return `${percentage < 0 ? `-` : "+"}${setRoundedPrecision(
6
6
  Math.abs(percentage),
7
7
  {
8
8
  decimals: 0,
9
9
  decimalsWhenSmall: 1,
10
10
  },
11
- )}%`
12
- }
11
+ )}%`;
12
+ };
@@ -1,6 +1,6 @@
1
- import { createDetailedMessage } from "@jsenv/log"
1
+ import { createDetailedMessage } from "@jsenv/log";
2
2
 
3
- import { assertMetrics } from "./assertions.js"
3
+ import { assertMetrics } from "./assertions.js";
4
4
 
5
5
  export const measureMultipleTimes = async (
6
6
  measure,
@@ -8,53 +8,53 @@ export const measureMultipleTimes = async (
8
8
  { msToWaitBetweenEachIteration = 0 } = {},
9
9
  ) => {
10
10
  if (typeof measure !== "function") {
11
- throw new TypeError(`measure must be a function, received ${measure}`)
11
+ throw new TypeError(`measure must be a function, received ${measure}`);
12
12
  }
13
13
  if (typeof iterationCount !== "number") {
14
14
  throw new TypeError(
15
15
  `iterationCount must be a number, received ${iterationCount}`,
16
- )
16
+ );
17
17
  }
18
18
 
19
- const firstIterationMetrics = await measure()
20
- assertMetrics(firstIterationMetrics)
21
- const firstIterationMetricNames = Object.keys(firstIterationMetrics)
19
+ const firstIterationMetrics = await measure();
20
+ assertMetrics(firstIterationMetrics);
21
+ const firstIterationMetricNames = Object.keys(firstIterationMetrics);
22
22
  if (firstIterationMetricNames.length === 0) {
23
23
  throw new Error(
24
24
  `measure must return a non empty object, received an object without key`,
25
- )
25
+ );
26
26
  }
27
27
 
28
- const metricsWithIteration = {}
28
+ const metricsWithIteration = {};
29
29
  firstIterationMetricNames.forEach((metricName) => {
30
- const metric = firstIterationMetrics[metricName]
30
+ const metric = firstIterationMetrics[metricName];
31
31
  metricsWithIteration[metricName] = {
32
32
  values: [metric.value],
33
33
  unit: metric.unit,
34
- }
35
- })
34
+ };
35
+ });
36
36
 
37
37
  if (iterationCount === 1) {
38
- return metricsWithIteration
38
+ return metricsWithIteration;
39
39
  }
40
40
 
41
- const iterationArray = new Array(iterationCount - 1).fill()
41
+ const iterationArray = new Array(iterationCount - 1).fill();
42
42
  await iterationArray.reduce(async (previous, _, index) => {
43
- await previous
43
+ await previous;
44
44
 
45
- const currentMetrics = await measure()
46
- assertMetrics(currentMetrics)
47
- const currentIterationMetricNames = Object.keys(currentMetrics)
45
+ const currentMetrics = await measure();
46
+ assertMetrics(currentMetrics);
47
+ const currentIterationMetricNames = Object.keys(currentMetrics);
48
48
  const missingMetricNamesInCurrentIteration =
49
49
  firstIterationMetricNames.filter(
50
50
  (firstIterationMetricName) =>
51
51
  !currentIterationMetricNames.includes(firstIterationMetricName),
52
- )
52
+ );
53
53
  const extraMetricNamesInCurrentIteration =
54
54
  currentIterationMetricNames.filter(
55
55
  (currentIterationMetricName) =>
56
56
  !firstIterationMetricNames.includes(currentIterationMetricName),
57
- )
57
+ );
58
58
  if (
59
59
  missingMetricNamesInCurrentIteration.length ||
60
60
  extraMetricNamesInCurrentIteration.length
@@ -65,12 +65,12 @@ export const measureMultipleTimes = async (
65
65
  extraMetricNamesInCurrentIteration,
66
66
  iterationIndex: index,
67
67
  }),
68
- )
68
+ );
69
69
  }
70
70
 
71
71
  firstIterationMetricNames.forEach((metricName) => {
72
- const metricWithIteration = metricsWithIteration[metricName]
73
- const currentMetric = currentMetrics[metricName]
72
+ const metricWithIteration = metricsWithIteration[metricName];
73
+ const currentMetric = currentMetrics[metricName];
74
74
  if (currentMetric.unit !== metricWithIteration.unit) {
75
75
  throw new Error(
76
76
  createDetailedMessage(
@@ -81,19 +81,19 @@ export const measureMultipleTimes = async (
81
81
  "metric name": metricName,
82
82
  },
83
83
  ),
84
- )
84
+ );
85
85
  }
86
- metricWithIteration.values.push(currentMetric.value)
87
- })
86
+ metricWithIteration.values.push(currentMetric.value);
87
+ });
88
88
 
89
89
  // await a little bit to let previous execution the time to potentially clean up things
90
90
  await new Promise((resolve) => {
91
- setTimeout(resolve, msToWaitBetweenEachIteration)
92
- })
93
- }, Promise.resolve())
91
+ setTimeout(resolve, msToWaitBetweenEachIteration);
92
+ });
93
+ }, Promise.resolve());
94
94
 
95
- return metricsWithIteration
96
- }
95
+ return metricsWithIteration;
96
+ };
97
97
 
98
98
  const createVariableMetricNamesErrorMessage = ({
99
99
  missingMetricNamesInCurrentIteration,
@@ -116,5 +116,5 @@ const createVariableMetricNamesErrorMessage = ({
116
116
  }
117
117
  : {}),
118
118
  },
119
- )
120
- }
119
+ );
120
+ };
@@ -8,21 +8,21 @@
8
8
  */
9
9
 
10
10
  export const median = (numbers) => {
11
- const numberCount = numbers.length
12
- const numbersSorted = numbers.slice()
13
- numbersSorted.sort()
11
+ const numberCount = numbers.length;
12
+ const numbersSorted = numbers.slice();
13
+ numbersSorted.sort();
14
14
 
15
- const isEven = numberCount % 2 === 0
15
+ const isEven = numberCount % 2 === 0;
16
16
  if (isEven) {
17
- const rightMiddleNumberIndex = numberCount / 2
18
- const leftMiddleNumberIndex = rightMiddleNumberIndex - 1
19
- const leftMiddleNumber = numbersSorted[leftMiddleNumberIndex]
20
- const rightMiddleNumber = numbersSorted[rightMiddleNumberIndex]
21
- const medianNumber = (leftMiddleNumber + rightMiddleNumber) / 2
22
- return medianNumber
17
+ const rightMiddleNumberIndex = numberCount / 2;
18
+ const leftMiddleNumberIndex = rightMiddleNumberIndex - 1;
19
+ const leftMiddleNumber = numbersSorted[leftMiddleNumberIndex];
20
+ const rightMiddleNumber = numbersSorted[rightMiddleNumberIndex];
21
+ const medianNumber = (leftMiddleNumber + rightMiddleNumber) / 2;
22
+ return medianNumber;
23
23
  }
24
24
 
25
- const medianNumberIndex = (numberCount - 1) / 2
26
- const medianNumber = numbersSorted[medianNumberIndex]
27
- return medianNumber
28
- }
25
+ const medianNumberIndex = (numberCount - 1) / 2;
26
+ const medianNumber = numbersSorted[medianNumberIndex];
27
+ return medianNumber;
28
+ };
package/src/main.js CHANGED
@@ -1,5 +1,5 @@
1
- export { readGitHubWorkflowEnv } from "@jsenv/github-pull-request-impact"
1
+ export { readGitHubWorkflowEnv } from "@jsenv/github-pull-request-impact";
2
2
 
3
- export { startMeasures } from "./startMeasures.js"
4
- export { importMetricFromFiles } from "./importMetricFromFiles.js"
5
- export { reportPerformanceImpact } from "./reportPerformanceImpact.js"
3
+ export { startMeasures } from "./startMeasures.js";
4
+ export { importMetricFromFiles } from "./importMetricFromFiles.js";
5
+ export { reportPerformanceImpact } from "./reportPerformanceImpact.js";
@@ -1,10 +1,10 @@
1
- import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
2
- import { commentGitHubPullRequestImpact } from "@jsenv/github-pull-request-impact"
3
- import { importOneExportFromFile } from "@jsenv/dynamic-import-worker"
1
+ import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem";
2
+ import { commentGitHubPullRequestImpact } from "@jsenv/github-pull-request-impact";
3
+ import { importOneExportFromFile } from "@jsenv/dynamic-import-worker";
4
4
 
5
- import { assertPerformanceReport } from "./internal/assertions.js"
6
- import { createPerfImpactComment } from "./internal/comment/createPerfImpactComment.js"
7
- import { jsenvCommentParameters } from "./internal/comment/jsenvCommentParameters.js"
5
+ import { assertPerformanceReport } from "./internal/assertions.js";
6
+ import { createPerfImpactComment } from "./internal/comment/createPerfImpactComment.js";
7
+ import { jsenvCommentParameters } from "./internal/comment/jsenvCommentParameters.js";
8
8
 
9
9
  export const reportPerformanceImpact = async ({
10
10
  logLevel,
@@ -26,14 +26,14 @@ export const reportPerformanceImpact = async ({
26
26
  runLink,
27
27
  commitInGeneratedByInfo,
28
28
  }) => {
29
- rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
29
+ rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl);
30
30
  if (performanceReportUrl === "string") {
31
- performanceReportUrl = new URL(performanceReportUrl, rootDirectoryUrl).href
31
+ performanceReportUrl = new URL(performanceReportUrl, rootDirectoryUrl).href;
32
32
  } else if (performanceReportUrl instanceof URL) {
33
33
  } else {
34
34
  throw new TypeError(
35
35
  `performanceReportUrl must be a string or an url but received ${performanceReportUrl}`,
36
- )
36
+ );
37
37
  }
38
38
 
39
39
  return commentGitHubPullRequestImpact({
@@ -48,12 +48,12 @@ export const reportPerformanceImpact = async ({
48
48
  pullRequestNumber,
49
49
 
50
50
  collectInfo: async ({ execCommandInRootDirectory }) => {
51
- await execCommandInRootDirectory(installCommand)
51
+ await execCommandInRootDirectory(installCommand);
52
52
  const performanceReport = await importOneExportFromFile(
53
53
  performanceReportUrl,
54
- )
55
- assertPerformanceReport(performanceReport)
56
- return { version: 1, data: performanceReport }
54
+ );
55
+ assertPerformanceReport(performanceReport);
56
+ return { version: 1, data: performanceReport };
57
57
  },
58
58
  commentIdentifier: `<!-- Generated by @jsenv/performance-impact -->`,
59
59
  createCommentForComparison: ({
@@ -70,13 +70,13 @@ export const reportPerformanceImpact = async ({
70
70
  isPerformanceImpactBig,
71
71
  formatGroupSummary,
72
72
  formatPerformanceImpactCell,
73
- })
73
+ });
74
74
  },
75
75
  generatedByLink: {
76
- url: "https://github.com/jsenv/workflow/tree/main/packages/jsenv-performance-impact",
76
+ url: "https://github.com/jsenv/workflow/tree/main/packages/performance-impact",
77
77
  text: "@jsenv/performance-impact",
78
78
  },
79
79
  runLink,
80
80
  commitInGeneratedByInfo,
81
- })
82
- }
81
+ });
82
+ };
@@ -1,6 +1,6 @@
1
- import { resourceUsage, memoryUsage, emitWarning } from "node:process"
2
- import v8 from "node:v8"
3
- import { runInNewContext } from "node:vm"
1
+ import { resourceUsage, memoryUsage, emitWarning } from "node:process";
2
+ import v8 from "node:v8";
3
+ import { runInNewContext } from "node:vm";
4
4
 
5
5
  export const startMeasures = ({
6
6
  duration = true, // will be in milliseconds
@@ -9,48 +9,49 @@ export const startMeasures = ({
9
9
  gc = false,
10
10
  } = {}) => {
11
11
  if (gc && !global.gc) {
12
- v8.setFlagsFromString("--expose_gc")
13
- global.gc = runInNewContext("gc")
12
+ v8.setFlagsFromString("--expose_gc");
13
+ global.gc = runInNewContext("gc");
14
14
  emitWarning(`node must be started with --expose-gc`, {
15
15
  CODE: "EXPOSE_GC_IS_MISSING",
16
16
  detail: "global.gc forced with v8.setFlagsFromString",
17
- })
17
+ });
18
18
  }
19
19
 
20
- const measures = []
20
+ const measures = [];
21
21
  if (duration) {
22
- const beforeMs = Date.now()
22
+ const beforeMs = Date.now();
23
23
  measures.push(() => {
24
- const afterMs = Date.now()
25
- const duration = afterMs - beforeMs
24
+ const afterMs = Date.now();
25
+ const duration = afterMs - beforeMs;
26
26
  return {
27
27
  duration,
28
- }
29
- })
28
+ };
29
+ });
30
30
  }
31
31
  if (filesystem) {
32
- const beforeRessourceUsage = resourceUsage()
32
+ const beforeRessourceUsage = resourceUsage();
33
33
  measures.push(() => {
34
- const afterRessourceUsage = resourceUsage()
35
- const fsRead = afterRessourceUsage.fsRead - beforeRessourceUsage.fsRead
36
- const fsWrite = afterRessourceUsage.fsWrite - beforeRessourceUsage.fsWrite
34
+ const afterRessourceUsage = resourceUsage();
35
+ const fsRead = afterRessourceUsage.fsRead - beforeRessourceUsage.fsRead;
36
+ const fsWrite =
37
+ afterRessourceUsage.fsWrite - beforeRessourceUsage.fsWrite;
37
38
  return {
38
39
  fsRead,
39
40
  fsWrite,
40
- }
41
- })
41
+ };
42
+ });
42
43
  }
43
44
 
44
45
  if (memoryHeap) {
45
46
  if (gc) {
46
- global.gc()
47
+ global.gc();
47
48
  }
48
- const beforeMemoryUsage = memoryUsage()
49
+ const beforeMemoryUsage = memoryUsage();
49
50
  measures.push(() => {
50
51
  if (gc) {
51
- global.gc()
52
+ global.gc();
52
53
  }
53
- const afterMemoryUsage = memoryUsage()
54
+ const afterMemoryUsage = memoryUsage();
54
55
  return {
55
56
  // total means "allocated"
56
57
  memoryHeapTotal:
@@ -60,20 +61,20 @@ export const startMeasures = ({
60
61
  rss: afterMemoryUsage.rss - beforeMemoryUsage.rss,
61
62
  arrayBuffers:
62
63
  afterMemoryUsage.arrayBuffers - beforeMemoryUsage.arrayBuffers,
63
- }
64
- })
64
+ };
65
+ });
65
66
  }
66
67
 
67
68
  const stop = () => {
68
- let metrics = {}
69
+ let metrics = {};
69
70
  measures.forEach((measure) => {
70
71
  metrics = {
71
72
  ...metrics,
72
73
  ...measure(),
73
- }
74
- })
75
- return metrics
76
- }
74
+ };
75
+ });
76
+ return metrics;
77
+ };
77
78
 
78
- return { stop }
79
- }
79
+ return { stop };
80
+ };