1
- import { Reflection , ContainerReflection } from '../../models/reflections/index ' ;
1
+ import { Reflection , ContainerReflection , DeclarationReflection } from '../../models' ;
2
2
import { ReflectionCategory } from '../../models/ReflectionCategory' ;
3
- import { SourceDirectory } from '../../models/sources/directory' ;
4
3
import { Component , ConverterComponent } from '../components' ;
5
4
import { Converter } from '../converter' ;
6
5
import { Context } from '../context' ;
7
- import { GroupPlugin } from './GroupPlugin' ;
6
+ import { Option } from '../../utils/component' ;
7
+ import { ParameterType } from '../../utils/options/declaration' ;
8
+ import { Comment } from '../../models/comments/index' ;
8
9
9
10
/**
10
11
* A handler that sorts and categorizes the found reflections in the resolving phase.
@@ -13,19 +14,57 @@ import { GroupPlugin } from './GroupPlugin';
13
14
*/
14
15
@Component ( { name : 'category' } )
15
16
export class CategoryPlugin extends ConverterComponent {
16
- /**
17
- * Define the sort order of categories. By default, sort alphabetically.
18
- */
17
+ @Option ( {
18
+ name : 'defaultCategory' ,
19
+ help : 'Specifies the default category for reflections without a category.' ,
20
+ type : ParameterType . String ,
21
+ defaultValue : 'Other'
22
+ } )
23
+ defaultCategory ! : string ;
24
+
25
+ @Option ( {
26
+ name : 'categoryOrder' ,
27
+ help : 'Specifies the order in which categories appear. * indicates the relative order for categories not in the list.' ,
28
+ type : ParameterType . Array
29
+ } )
30
+ categoryOrder ! : string [ ] ;
31
+
32
+ @Option ( {
33
+ name : 'categorizeByGroup' ,
34
+ help : 'Specifies whether categorization will be done at the group level.' ,
35
+ type : ParameterType . Boolean ,
36
+ defaultValue : true
37
+ } )
38
+ categorizeByGroup ! : boolean ;
39
+
40
+ // For use in static methods
41
+ static defaultCategory = 'Other' ;
19
42
static WEIGHTS : string [ ] = [ ] ;
20
43
21
44
/**
22
45
* Create a new CategoryPlugin instance.
23
46
*/
24
47
initialize ( ) {
25
48
this . listenTo ( this . owner , {
49
+ [ Converter . EVENT_BEGIN ] : this . onBegin ,
26
50
[ Converter . EVENT_RESOLVE ] : this . onResolve ,
27
51
[ Converter . EVENT_RESOLVE_END ] : this . onEndResolve
28
- } ) ;
52
+ } , undefined , - 200 ) ;
53
+ }
54
+
55
+ /**
56
+ * Triggered when the converter begins converting a project.
57
+ *
58
+ * @param context The context object describing the current state the converter is in.
59
+ */
60
+ private onBegin ( context : Context ) {
61
+ // Set up static properties
62
+ if ( this . defaultCategory ) {
63
+ CategoryPlugin . defaultCategory = this . defaultCategory ;
64
+ }
65
+ if ( this . categoryOrder ) {
66
+ CategoryPlugin . WEIGHTS = this . categoryOrder ;
67
+ }
29
68
}
30
69
31
70
/**
@@ -36,13 +75,7 @@ export class CategoryPlugin extends ConverterComponent {
36
75
*/
37
76
private onResolve ( context : Context , reflection : Reflection ) {
38
77
if ( reflection instanceof ContainerReflection ) {
39
- if ( reflection . children && reflection . children . length > 0 ) {
40
- reflection . children . sort ( GroupPlugin . sortCallback ) ;
41
- reflection . categories = CategoryPlugin . getReflectionCategories ( reflection . children ) ;
42
- }
43
- if ( reflection . categories && reflection . categories . length > 1 ) {
44
- reflection . categories . sort ( CategoryPlugin . sortCatCallback ) ;
45
- }
78
+ this . categorize ( reflection ) ;
46
79
}
47
80
}
48
81
@@ -52,32 +85,44 @@ export class CategoryPlugin extends ConverterComponent {
52
85
* @param context The context object describing the current state the converter is in.
53
86
*/
54
87
private onEndResolve ( context : Context ) {
55
- function walkDirectory ( directory : SourceDirectory ) {
56
- directory . categories = CategoryPlugin . getReflectionCategories ( directory . getAllReflections ( ) ) ;
88
+ const project = context . project ;
89
+ this . categorize ( project ) ;
90
+ }
57
91
58
- for ( let key in directory . directories ) {
59
- if ( ! directory . directories . hasOwnProperty ( key ) ) {
60
- continue ;
61
- }
62
- walkDirectory ( directory . directories [ key ] ) ;
63
- }
92
+ private categorize ( obj : ContainerReflection ) {
93
+ if ( this . categorizeByGroup ) {
94
+ this . groupCategorize ( obj ) ;
95
+ } else {
96
+ this . lumpCategorize ( obj ) ;
64
97
}
98
+ }
65
99
66
- const project = context . project ;
67
- if ( project . children && project . children . length > 0 ) {
68
- project . children . sort ( GroupPlugin . sortCallback ) ;
69
- project . categories = CategoryPlugin . getReflectionCategories ( project . children ) ;
70
- }
71
- if ( project . categories && project . categories . length > 1 ) {
72
- project . categories . sort ( CategoryPlugin . sortCatCallback ) ;
100
+ private groupCategorize ( obj : ContainerReflection ) {
101
+ if ( ! obj . groups || obj . groups . length === 0 ) {
102
+ return ;
73
103
}
74
-
75
- walkDirectory ( project . directory ) ;
76
- project . files . forEach ( ( file ) => {
77
- file . categories = CategoryPlugin . getReflectionCategories ( file . reflections ) ;
104
+ obj . groups . forEach ( ( group ) => {
105
+ group . categories = CategoryPlugin . getReflectionCategories ( group . children ) ;
106
+ if ( group . categories && group . categories . length > 1 ) {
107
+ group . categories . sort ( CategoryPlugin . sortCatCallback ) ;
108
+ } else if ( group . categories . length === 1 && group . categories [ 0 ] . title === CategoryPlugin . defaultCategory ) {
109
+ // no categories if everything is uncategorized
110
+ group . categories = undefined ;
111
+ }
78
112
} ) ;
79
113
}
80
114
115
+ private lumpCategorize ( obj : ContainerReflection ) {
116
+ if ( obj instanceof ContainerReflection ) {
117
+ if ( obj . children && obj . children . length > 0 ) {
118
+ obj . categories = CategoryPlugin . getReflectionCategories ( obj . children ) ;
119
+ }
120
+ if ( obj . categories && obj . categories . length > 1 ) {
121
+ obj . categories . sort ( CategoryPlugin . sortCatCallback ) ;
122
+ }
123
+ }
124
+ }
125
+
81
126
/**
82
127
* Create a categorized representation of the given list of reflections.
83
128
*
@@ -86,23 +131,26 @@ export class CategoryPlugin extends ConverterComponent {
86
131
*/
87
132
static getReflectionCategories ( reflections : Reflection [ ] ) : ReflectionCategory [ ] {
88
133
const categories : ReflectionCategory [ ] = [ ] ;
134
+ let defaultCat : ReflectionCategory | undefined ;
89
135
reflections . forEach ( ( child ) => {
90
136
const childCat = CategoryPlugin . getCategory ( child ) ;
91
137
if ( childCat === '' ) {
92
- return ;
93
- }
94
- for ( let i = 0 ; i < categories . length ; i ++ ) {
95
- const category = categories [ i ] ;
96
-
97
- if ( category . title !== childCat ) {
98
- continue ;
138
+ if ( ! defaultCat ) {
139
+ defaultCat = categories . find ( category => category . title === CategoryPlugin . defaultCategory ) ;
140
+ if ( ! defaultCat ) {
141
+ defaultCat = new ReflectionCategory ( CategoryPlugin . defaultCategory ) ;
142
+ categories . push ( defaultCat ) ;
143
+ }
99
144
}
100
-
145
+ defaultCat . children . push ( child ) ;
146
+ return ;
147
+ }
148
+ let category = categories . find ( cat => cat . title === childCat ) ;
149
+ if ( category ) {
101
150
category . children . push ( child ) ;
102
151
return ;
103
152
}
104
-
105
- const category = new ReflectionCategory ( childCat ) ;
153
+ category = new ReflectionCategory ( childCat ) ;
106
154
category . children . push ( child ) ;
107
155
categories . push ( category ) ;
108
156
} ) ;
@@ -116,29 +164,31 @@ export class CategoryPlugin extends ConverterComponent {
116
164
* @returns The category the reflection belongs to
117
165
*/
118
166
static getCategory ( reflection : Reflection ) : string {
119
- if ( reflection . comment ) {
120
- const tags = reflection . comment . tags ;
167
+ function extractCategoryTag ( comment : Comment ) {
168
+ const tags = comment . tags ;
121
169
if ( tags ) {
122
170
for ( let i = 0 ; i < tags . length ; i ++ ) {
123
171
if ( tags [ i ] . tagName === 'category' ) {
124
172
let tag = tags [ i ] . text ;
125
- return ( tag . charAt ( 0 ) . toUpperCase ( ) + tag . slice ( 1 ) . toLowerCase ( ) ) . trim ( ) ;
173
+ return tag . trim ( ) ;
126
174
}
127
175
}
128
176
}
177
+ return '' ;
129
178
}
130
- return '' ;
131
- }
132
179
133
- /**
134
- * Callback used to sort reflections by name.
135
- *
136
- * @param a The left reflection to sort.
137
- * @param b The right reflection to sort.
138
- * @returns The sorting weight.
139
- */
140
- static sortCallback ( a : Reflection , b : Reflection ) : number {
141
- return a . name > b . name ? 1 : - 1 ;
180
+ let category = '' ;
181
+ if ( reflection . comment ) {
182
+ category = extractCategoryTag ( reflection . comment ) ;
183
+ } else if ( reflection instanceof DeclarationReflection && reflection . signatures ) {
184
+ // If a reflection has signatures, use the first category tag amongst them
185
+ reflection . signatures . forEach ( sig => {
186
+ if ( sig . comment && category === '' ) {
187
+ category = extractCategoryTag ( sig . comment ) ;
188
+ }
189
+ } ) ;
190
+ }
191
+ return category ;
142
192
}
143
193
144
194
/**
@@ -149,16 +199,16 @@ export class CategoryPlugin extends ConverterComponent {
149
199
* @returns The sorting weight.
150
200
*/
151
201
static sortCatCallback ( a : ReflectionCategory , b : ReflectionCategory ) : number {
152
- const aWeight = CategoryPlugin . WEIGHTS . indexOf ( a . title ) ;
153
- const bWeight = CategoryPlugin . WEIGHTS . indexOf ( b . title ) ;
154
- if ( aWeight < 0 && bWeight < 0 ) {
155
- return a . title > b . title ? 1 : - 1 ;
156
- }
157
- if ( aWeight < 0 ) {
158
- return 1 ;
202
+ let aWeight = CategoryPlugin . WEIGHTS . indexOf ( a . title ) ;
203
+ let bWeight = CategoryPlugin . WEIGHTS . indexOf ( b . title ) ;
204
+ if ( aWeight === - 1 || bWeight === - 1 ) {
205
+ let asteriskIndex = CategoryPlugin . WEIGHTS . indexOf ( '*' ) ;
206
+ if ( asteriskIndex === - 1 ) { asteriskIndex = CategoryPlugin . WEIGHTS . length ; }
207
+ if ( aWeight === - 1 ) { aWeight = asteriskIndex ; }
208
+ if ( bWeight === - 1 ) { bWeight = asteriskIndex ; }
159
209
}
160
- if ( bWeight < 0 ) {
161
- return - 1 ;
210
+ if ( aWeight === bWeight ) {
211
+ return a . title > b . title ? 1 : - 1 ;
162
212
}
163
213
return aWeight - bWeight ;
164
214
}
0 commit comments