@@ -2,24 +2,27 @@ import Churn from "./churn/churn";
22import Complexity from "./complexity" ;
33import { Options , Path , Sort } from "./types" ;
44import { buildDebugger } from "../utils" ;
5+ import * as NodePath from "path" ;
56
67const DEFAULT_CHURN = 1 ;
78const DEFAULT_COMPLEXITY = 1 ;
89
910const internal = { debug : buildDebugger ( "statistics" ) } ;
1011
12+ export interface IStatistics {
13+ path : Path ;
14+ churn : number ;
15+ complexity : number ;
16+ score : number ;
17+ }
18+
1119export default class Statistics {
1220 public readonly path : Path ;
1321 public readonly churn : number ;
1422 public readonly complexity : number ;
1523 public readonly score : number ;
1624
17- constructor ( path : Path , churn : number , complexity : number ) {
18- this . path = path ;
19- this . churn = churn ;
20- this . complexity = complexity ;
21- this . score = this . churn * this . complexity ;
22- }
25+ private readonly directories : string [ ] ;
2326
2427 public static async compute (
2528 options : Options
@@ -31,24 +34,92 @@ export default class Statistics {
3134 const paths = Array . from ( churns . keys ( ) ) ;
3235 const complexities = await Complexity . compute ( paths , options ) ;
3336
34- const statistics = paths
35- . map ( toStatistics ( churns , complexities ) )
36- . sort ( sort ( options . sort ) )
37- . filter ( limit ( options . limit ) ) ;
37+ const statistics = paths . map ( Statistics . toStatistics ( churns , complexities ) ) ;
3838
39- return toMap ( statistics ) ;
39+ const mapOfStatistics = options . directories
40+ ? Statistics . toDirectoryMap ( statistics )
41+ : Statistics . toFileMap ( statistics ) ;
42+
43+ return new Map (
44+ [ ...mapOfStatistics . entries ( ) ]
45+ . sort ( ( [ , v1 ] , [ , v2 ] ) => sort ( options . sort ) ( v1 , v2 ) )
46+ . filter ( ( [ , v ] , index ) => limit ( options . limit ) ( v , index ) )
47+ ) ;
4048 }
41- }
4249
43- function toStatistics (
44- churns : Map < Path , number > ,
45- complexities : Map < Path , number >
46- ) : ( path : Path ) => Statistics {
47- return ( path ) : Statistics => {
48- const churn = churns . get ( path ) || DEFAULT_CHURN ;
49- const complexity = complexities . get ( path ) || DEFAULT_COMPLEXITY ;
50- return new Statistics ( path , churn , complexity ) ;
51- } ;
50+ public static toStatistics (
51+ churns : Map < Path , number > ,
52+ complexities : Map < Path , number >
53+ ) : ( path : Path ) => Statistics {
54+ return ( path ) : Statistics => {
55+ const churn = churns . get ( path ) || DEFAULT_CHURN ;
56+ const complexity = complexities . get ( path ) || DEFAULT_COMPLEXITY ;
57+ return new Statistics ( path , churn , complexity ) ;
58+ } ;
59+ }
60+
61+ private constructor ( path : Path , churn : number , complexity : number ) {
62+ this . path = path ;
63+ this . churn = churn ;
64+ this . complexity = complexity ;
65+ this . directories = this . findDirectoriesForFile ( path ) ;
66+ this . score = this . churn * this . complexity ;
67+ }
68+
69+ private findDirectoriesForFile ( path : string ) : string [ ] {
70+ const directories : string [ ] = [ ] ;
71+ const pathChunks = NodePath . parse ( path ) . dir . split ( NodePath . sep ) ;
72+ pathChunks . forEach ( ( chunk ) => {
73+ const parentDir = directories . slice ( - 1 ) ;
74+ const directory = parentDir . length
75+ ? parentDir + NodePath . sep + chunk
76+ : chunk ;
77+ directories . push ( directory ) ;
78+ } ) ;
79+ return directories . filter ( ( d ) => d . length > 0 ) ;
80+ }
81+
82+ private static toFileMap ( statistics : Statistics [ ] ) : Map < Path , Statistics > {
83+ return statistics . reduce ( ( map : Map < Path , Statistics > , statistics ) => {
84+ map . set ( statistics . path , statistics ) ;
85+ return map ;
86+ } , new Map ( ) ) ;
87+ }
88+
89+ private static toDirectoryMap (
90+ allStatistics : Statistics [ ]
91+ ) : Map < string , Statistics > {
92+ return allStatistics . reduce ( ( map , statisticsForFile ) => {
93+ statisticsForFile . directories . forEach ( ( directoryForFile ) => {
94+ computeStatisticsForDirectory ( map , directoryForFile , statisticsForFile ) ;
95+ } ) ;
96+ return map ;
97+ } , new Map < string , Statistics > ( ) ) ;
98+
99+ function computeStatisticsForDirectory (
100+ map : Map < string , Statistics > ,
101+ dir : string ,
102+ statisticsForFile : Statistics
103+ ) {
104+ const statisticsForDir = map . get ( dir ) ;
105+ const churn =
106+ statisticsForFile . churn +
107+ ( statisticsForDir ? statisticsForDir . churn : 0 ) ;
108+ const complexity =
109+ statisticsForFile . complexity +
110+ ( statisticsForDir ? statisticsForDir . complexity : 0 ) ;
111+ map . set ( dir , new Statistics ( dir , churn , complexity ) ) ;
112+ }
113+ }
114+
115+ public toState ( ) : IStatistics {
116+ return {
117+ path : this . path ,
118+ churn : this . churn ,
119+ complexity : this . complexity ,
120+ score : this . score ,
121+ } ;
122+ }
52123}
53124
54125function limit (
@@ -80,10 +151,3 @@ function sort(sort: Sort | undefined) {
80151 return 0 ;
81152 } ;
82153}
83-
84- function toMap ( statistics : Statistics [ ] ) : Map < Path , Statistics > {
85- return statistics . reduce ( ( map : Map < Path , Statistics > , statistics ) => {
86- map . set ( statistics . path , statistics ) ;
87- return map ;
88- } , new Map ( ) ) ;
89- }
0 commit comments