lighthouse
Version:
Automated auditing, performance metrics, and best practices for the web.
92 lines (77 loc) • 2.87 kB
JavaScript
/**
* @license
* Copyright 2018 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {Audit} from './audits/audit.js';
/**
* Clamp figure to 2 decimal places
* @param {number} val
* @return {number}
*/
const clampTo2Decimals = val => Math.round(val * 100) / 100;
class ReportScoring {
/**
* Computes the weighted-average of the score of the list of items.
* @param {Array<{score: number|null, weight: number}>} items
* @return {number|null}
*/
static arithmeticMean(items) {
// Filter down to just the items with a weight as they have no effect on score
items = items.filter(item => item.weight > 0);
// If there is 1 null score, return a null average
if (items.some(item => item.score === null)) return null;
const results = items.reduce(
(result, item) => {
const score = item.score;
const weight = item.weight;
return {
weight: result.weight + weight,
sum: result.sum + /** @type {number} */ (score) * weight,
};
},
{weight: 0, sum: 0}
);
return clampTo2Decimals(results.sum / results.weight || 0);
}
/**
* Returns the report JSON object with computed scores.
* @param {Object<string, LH.Config.Category>} configCategories
* @param {Object<string, LH.RawIcu<LH.Audit.Result>>} resultsByAuditId
* @return {Object<string, LH.RawIcu<LH.Result.Category>>}
*/
static scoreAllCategories(configCategories, resultsByAuditId) {
/** @type {Record<string, LH.RawIcu<LH.Result.Category>>} */
const scoredCategories = {};
for (const [categoryId, configCategory] of Object.entries(configCategories)) {
// Copy category audit members
const auditRefs = configCategory.auditRefs.map(configMember => {
const member = {...configMember};
// If a result was not applicable, meaning its checks did not run against anything on
// the page, force its weight to 0. It will not count during the arithmeticMean() but
// will still be included in the final report json and displayed in the report as
// "Not Applicable".
const result = resultsByAuditId[member.id];
if (result.scoreDisplayMode === Audit.SCORING_MODES.NOT_APPLICABLE ||
result.scoreDisplayMode === Audit.SCORING_MODES.INFORMATIVE ||
result.scoreDisplayMode === Audit.SCORING_MODES.MANUAL) {
member.weight = 0;
}
return member;
});
const scores = auditRefs.map(auditRef => ({
score: resultsByAuditId[auditRef.id].score,
weight: auditRef.weight,
}));
const score = ReportScoring.arithmeticMean(scores);
scoredCategories[categoryId] = {
...configCategory,
auditRefs,
id: categoryId,
score,
};
}
return scoredCategories;
}
}
export {ReportScoring};