@@ -2,24 +2,27 @@ import Churn from "./churn/churn";
2
2
import Complexity from "./complexity" ;
3
3
import { Options , Path , Sort } from "./types" ;
4
4
import { buildDebugger } from "../utils" ;
5
+ import * as NodePath from "path" ;
5
6
6
7
const DEFAULT_CHURN = 1 ;
7
8
const DEFAULT_COMPLEXITY = 1 ;
8
9
9
10
const internal = { debug : buildDebugger ( "statistics" ) } ;
10
11
12
+ export interface IStatistics {
13
+ path : Path ;
14
+ churn : number ;
15
+ complexity : number ;
16
+ score : number ;
17
+ }
18
+
11
19
export default class Statistics {
12
20
public readonly path : Path ;
13
21
public readonly churn : number ;
14
22
public readonly complexity : number ;
15
23
public readonly score : number ;
16
24
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 [ ] ;
23
26
24
27
public static async compute (
25
28
options : Options
@@ -31,24 +34,92 @@ export default class Statistics {
31
34
const paths = Array . from ( churns . keys ( ) ) ;
32
35
const complexities = await Complexity . compute ( paths , options ) ;
33
36
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 ) ) ;
38
38
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
+ ) ;
40
48
}
41
- }
42
49
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
+ }
52
123
}
53
124
54
125
function limit (
@@ -80,10 +151,3 @@ function sort(sort: Sort | undefined) {
80
151
return 0 ;
81
152
} ;
82
153
}
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