1
+ // Todo[engine:node@>=7.0.0]: Replace with `Object.entries`
2
+ import entries from 'object.entries-ponyfill' ;
1
3
import iterateJsdoc from '../iterateJsdoc' ;
2
4
5
+ const defaultTags = {
6
+ file : {
7
+ initialCommentsOnly : true ,
8
+ mustExist : true ,
9
+ preventDuplicates : true ,
10
+ } ,
11
+ } ;
12
+
13
+ const setDefaults = ( state ) => {
14
+ // First iteration
15
+ if ( ! state . globalTags ) {
16
+ state . globalTags = { } ;
17
+ state . hasDuplicates = { } ;
18
+ state . hasTag = { } ;
19
+ state . hasNonCommentBeforeTag = { } ;
20
+ }
21
+ } ;
22
+
3
23
export default iterateJsdoc ( ( {
24
+ jsdocNode,
4
25
state,
5
26
utils,
6
27
} ) => {
7
- const targetTagName = utils . getPreferredTagName ( { tagName : 'file' } ) ;
28
+ const tags = defaultTags ;
8
29
9
- const hasFileOverview = targetTagName && utils . hasTag ( targetTagName ) ;
30
+ setDefaults ( state ) ;
10
31
11
- if ( state . hasFileOverview ) {
12
- state . hasDuplicate = hasFileOverview ;
32
+ for ( const tagName of Object . keys ( tags ) ) {
33
+ const targetTagName = utils . getPreferredTagName ( { tagName } ) ;
13
34
14
- return ;
15
- }
35
+ const hasTag = targetTagName && utils . hasTag ( targetTagName ) ;
36
+
37
+ state . hasTag [ tagName ] = hasTag || state . hasTag [ tagName ] ;
38
+
39
+ const hasDuplicate = state . hasDuplicates [ tagName ] ;
16
40
17
- state . hasFileOverview = hasFileOverview ;
41
+ if ( hasDuplicate === false ) {
42
+ // Was marked before, so if a tag now, is a dupe
43
+ state . hasDuplicates [ tagName ] = hasTag ;
44
+ } else if ( ! hasDuplicate && hasTag ) {
45
+ // No dupes set before, but has first tag, so change state
46
+ // from `undefined` to `false` so can detect next time
47
+ state . hasDuplicates [ tagName ] = false ;
48
+ state . hasNonCommentBeforeTag [ tagName ] = state . hasNonComment &&
49
+ state . hasNonComment < jsdocNode . start ;
50
+ }
51
+ }
18
52
} , {
19
53
exit ( { state, utils} ) {
20
- if ( state . hasFileOverview && ! state . hasDuplicate &&
21
- ! state . hasNonCommentBeforeFileOverview
22
- ) {
23
- return ;
24
- }
25
- const obj = utils . getPreferredTagNameObject ( { tagName : 'file' } ) ;
26
- if ( obj && obj . blocked ) {
27
- utils . reportSettings (
28
- `\`settings.jsdoc.tagNamePreference\` cannot block @${ obj . tagName } ` +
29
- 'for the `require-file-overview` rule' ,
30
- ) ;
31
- } else {
32
- const targetTagName = obj && obj . replacement || obj ;
33
- if ( state . hasDuplicate ) {
34
- utils . reportSettings (
35
- `Duplicate @${ targetTagName } ` ,
36
- ) ;
37
- } else if ( state . hasFileOverview &&
38
- state . hasNonCommentBeforeFileOverview
39
- ) {
54
+ setDefaults ( state ) ;
55
+ const tags = defaultTags ;
56
+
57
+ for ( const [ tagName , {
58
+ mustExist,
59
+ preventDuplicates,
60
+ initialCommentsOnly,
61
+ } ] of entries ( tags ) ) {
62
+ const obj = utils . getPreferredTagNameObject ( { tagName} ) ;
63
+ if ( obj && obj . blocked ) {
40
64
utils . reportSettings (
41
- `@${ targetTagName } should be at the beginning of the file` ,
65
+ `\`settings.jsdoc.tagNamePreference\` cannot block @${ obj . tagName } ` +
66
+ 'for the `require-file-overview` rule' ,
42
67
) ;
43
68
} else {
44
- utils . reportSettings ( `Missing @${ targetTagName } ` ) ;
69
+ const targetTagName = obj && obj . replacement || obj ;
70
+ if ( mustExist && ! state . hasTag [ tagName ] ) {
71
+ utils . reportSettings ( `Missing @${ targetTagName } ` ) ;
72
+ }
73
+ if ( preventDuplicates && state . hasDuplicates [ tagName ] ) {
74
+ utils . reportSettings (
75
+ `Duplicate @${ targetTagName } ` ,
76
+ ) ;
77
+ }
78
+ if ( initialCommentsOnly &&
79
+ state . hasNonCommentBeforeTag [ tagName ]
80
+ ) {
81
+ utils . reportSettings (
82
+ `@${ targetTagName } should be at the beginning of the file` ,
83
+ ) ;
84
+ }
45
85
}
46
86
}
47
87
} ,
@@ -50,7 +90,9 @@ export default iterateJsdoc(({
50
90
fixable : 'code' ,
51
91
type : 'suggestion' ,
52
92
} ,
53
- nonComment ( { state} ) {
54
- state . hasNonCommentBeforeFileOverview = ! state . hasFileOverview ;
93
+ nonComment ( { state, node} ) {
94
+ if ( ! state . hasNonComment ) {
95
+ state . hasNonComment = node . start ;
96
+ }
55
97
} ,
56
98
} ) ;
0 commit comments