@@ -29,33 +29,6 @@ export type ScoredReport = Omit<Report, 'plugins' | 'categories'> & {
2929 categories : ScoredCategoryConfig [ ] ;
3030} ;
3131
32- export function calculateScore < T extends { weight : number } > (
33- refs : T [ ] ,
34- scoreFn : ( ref : T ) => number ,
35- ) : number {
36- const { numerator, denominator } = refs . reduce (
37- ( acc , ref ) => {
38- const score = scoreFn ( ref ) ;
39- return {
40- numerator : acc . numerator + score * ref . weight ,
41- denominator : acc . denominator + ref . weight ,
42- } ;
43- } ,
44- { numerator : 0 , denominator : 0 } ,
45- ) ;
46- // No division by 0, otherwise we produce NaN
47- // This can be caused by:
48- // - empty category refs
49- // - categories with refs only containing weight of `0`
50- // both should get caught when validating the model
51- if ( ! numerator && ! denominator ) {
52- throw new Error (
53- '0 division for score. This can be caused by refs only weighted with 0 or empty refs' ,
54- ) ;
55- }
56- return numerator / denominator ;
57- }
58-
5932// eslint-disable-next-line max-lines-per-function
6033export function scoreReport ( report : Report ) : ScoredReport {
6134 const allScoredAuditsAndGroups = new Map <
@@ -119,3 +92,47 @@ export function scoreReport(report: Report): ScoredReport {
11992 categories : scoredCategories ,
12093 } ;
12194}
95+
96+ export function calculateScore < T extends { weight : number } > (
97+ refs : T [ ] ,
98+ scoreFn : ( ref : T ) => number ,
99+ ) : number {
100+ const validatedRefs = parseScoringParameters ( refs , scoreFn ) ;
101+ const { numerator, denominator } = validatedRefs . reduce (
102+ ( acc , ref ) => ( {
103+ numerator : acc . numerator + ref . score * ref . weight ,
104+ denominator : acc . denominator + ref . weight ,
105+ } ) ,
106+ { numerator : 0 , denominator : 0 } ,
107+ ) ;
108+
109+ return numerator / denominator ;
110+ }
111+
112+ function parseScoringParameters < T extends { weight : number } > (
113+ refs : T [ ] ,
114+ scoreFn : ( ref : T ) => number ,
115+ ) : { weight : number ; score : number } [ ] {
116+ if ( refs . length === 0 ) {
117+ throw new Error ( 'Reference array cannot be empty.' ) ;
118+ }
119+
120+ if ( refs . some ( ref => ref . weight < 0 ) ) {
121+ throw new Error ( 'Weight cannot be negative.' ) ;
122+ }
123+
124+ if ( refs . every ( ref => ref . weight === 0 ) ) {
125+ throw new Error ( 'All references cannot have zero weight.' ) ;
126+ }
127+
128+ const scoredRefs = refs . map ( ref => ( {
129+ weight : ref . weight ,
130+ score : scoreFn ( ref ) ,
131+ } ) ) ;
132+
133+ if ( scoredRefs . some ( ref => ref . score < 0 || ref . score > 1 ) ) {
134+ throw new Error ( 'All scores must be in range 0-1.' ) ;
135+ }
136+
137+ return scoredRefs ;
138+ }
0 commit comments