@@ -28,22 +28,19 @@ function inferParams(comment /*: Comment */) {
28
28
return comment ;
29
29
}
30
30
31
+ var inferredParams = path . node . params . map ( ( param , i ) =>
32
+ paramToDoc ( param , '' , i ) ) ;
33
+
34
+ var mergedParams = mergeTrees ( inferredParams , comment . params ) ;
35
+
31
36
// Then merge the trees. This is the hard part.
32
37
return _ . assign ( comment , {
33
- params : mergeTrees (
34
- path . node . params . map ( ( param , i ) => paramToDoc ( param , i , '' ) ) ,
35
- comment . params
36
- )
38
+ params : mergedParams
37
39
} ) ;
38
40
}
39
41
40
42
// Utility methods ============================================================
41
43
//
42
- function addPrefix ( doc /*: CommentTagNamed */ , prefix ) {
43
- return _ . assign ( doc , {
44
- name : prefix + doc . name
45
- } ) ;
46
- }
47
44
const PATH_SPLIT_CAPTURING = / ( \[ ] ) ? ( \. ) / g;
48
45
49
46
/**
@@ -57,114 +54,6 @@ function mapTags(tags) {
57
54
) ;
58
55
}
59
56
60
- // ___toDoc methods ============================================================
61
- //
62
- // These methods take Babel AST nodes and output equivalent JSDoc parameter tags.
63
- function destructuringObjectParamToDoc ( param , i , prefix ) /*: CommentTag */ {
64
- return {
65
- title : 'param' ,
66
- name : '$' + String ( i ) ,
67
- anonymous : true ,
68
- type : ( param . typeAnnotation && flowDoctrine ( param ) ) || {
69
- type : 'NameExpression' ,
70
- name : 'Object'
71
- } ,
72
- properties : param . properties . map ( prop =>
73
- destructuringPropertyToDoc ( prop , i , prefix ) )
74
- } ;
75
- }
76
-
77
- function destructuringPropertyToDoc (
78
- property ,
79
- i /*: number */ ,
80
- prefix /*: string */
81
- ) /*: CommentTag */ {
82
- switch ( property . type ) {
83
- case 'ObjectProperty' :
84
- // Object properties can rename their arguments, like
85
- // function f({ x: y })
86
- // We want to document that as x, not y: y is the internal name.
87
- // So we use the key. In the case where they don't rename,
88
- // key and value are the same.
89
- return paramToDoc ( property , i , prefix + '$' + String ( i ) + '.' ) ;
90
- case 'Identifier' :
91
- // if the destructuring type is an array, the elements
92
- // in it are identifiers
93
- return paramToDoc ( property , i , prefix + '$' + String ( i ) + '.' ) ;
94
- case 'RestProperty' :
95
- case 'RestElement' :
96
- case 'ObjectPattern' :
97
- return paramToDoc ( property , i , prefix + '$' + String ( i ) + '.' ) ;
98
- default :
99
- throw new Error ( `Unknown property encountered: ${ property . type } ` ) ;
100
- }
101
- }
102
-
103
- function destructuringObjectPropertyToDoc (
104
- param ,
105
- i /*: number */ ,
106
- prefix /*: string */
107
- ) /*: CommentTag */ {
108
- return _ . assign ( paramToDoc ( param . value , i , prefix ) , {
109
- name : prefix + param . key . name
110
- } ) ;
111
- }
112
-
113
- function destructuringArrayParamToDoc (
114
- param ,
115
- i /*: number */ ,
116
- prefix /*: string */
117
- ) /*: CommentTag */ {
118
- return {
119
- title : 'param' ,
120
- name : '$' + String ( i ) ,
121
- anonymous : true ,
122
- type : ( param . typeAnnotation && flowDoctrine ( param ) ) || {
123
- type : 'NameExpression' ,
124
- name : 'Array'
125
- } ,
126
- properties : param . elements . map ( element =>
127
- destructuringPropertyToDoc ( element , i , prefix ) )
128
- } ;
129
- }
130
-
131
- /**
132
- * Given a parameter like
133
- *
134
- * function a(b = 1)
135
- *
136
- * Format it as an optional parameter in JSDoc land
137
- *
138
- * @param {Object } param ESTree node
139
- * @returns {Object } JSDoc param
140
- */
141
- function paramWithDefaultToDoc ( param , i ) /*: CommentTag */ {
142
- const newParam = paramToDoc ( param . left , i , '' ) ;
143
-
144
- return _ . assign ( newParam , {
145
- default : generate ( param . right ) . code ,
146
- type : {
147
- type : 'OptionalType' ,
148
- expression : newParam . type
149
- }
150
- } ) ;
151
- }
152
-
153
- function restParamToDoc ( param ) /*: CommentTag */ {
154
- let type /*: DoctrineType */ = {
155
- type : 'RestType'
156
- } ;
157
- if ( param . typeAnnotation ) {
158
- type . expression = flowDoctrine ( param . typeAnnotation . typeAnnotation ) ;
159
- }
160
- return {
161
- title : 'param' ,
162
- name : param . argument . name ,
163
- lineNumber : param . loc . start . line ,
164
- type
165
- } ;
166
- }
167
-
168
57
/**
169
58
* Babel parses JavaScript source code and produces an abstract syntax
170
59
* tree that includes methods and their arguments. This function takes
@@ -184,27 +73,124 @@ function restParamToDoc(param) /*: CommentTag */ {
184
73
*/
185
74
function paramToDoc (
186
75
param ,
187
- i /*: number */ ,
188
- prefix /*: string */
189
- ) /*: CommentTag */ {
190
- // ES6 default
76
+ prefix /*: string */ ,
77
+ i /*: ?number */
78
+ ) /*: CommentTag|Array<CommentTag> */ {
79
+ const autoName = '$' + String ( i ) ;
80
+ const prefixedName = prefix + '.' + param . name ;
81
+
191
82
switch ( param . type ) {
192
83
case 'AssignmentPattern' : // (a = b)
193
- return addPrefix ( paramWithDefaultToDoc ( param , i ) , prefix ) ;
84
+ const newAssignmentParam = paramToDoc ( param . left , '' , i ) ;
85
+
86
+ if ( Array . isArray ( newAssignmentParam ) ) {
87
+ throw new Error ( 'Encountered an unexpected parameter type' ) ;
88
+ }
89
+
90
+ return _ . assign ( newAssignmentParam , {
91
+ default : generate ( param . right , {
92
+ compact : true
93
+ } ) . code ,
94
+ type : {
95
+ type : 'OptionalType' ,
96
+ expression : newAssignmentParam . type
97
+ }
98
+ } ) ;
99
+ // ObjectPattern <AssignmentProperty | RestElement>
194
100
case 'ObjectPattern' : // { a }
195
- return destructuringObjectParamToDoc ( param , i , prefix ) ;
196
- case 'ArrayPattern' :
197
- return destructuringArrayParamToDoc ( param , i , prefix ) ;
198
- // TODO: do we need both?
101
+ if ( prefix === '' ) {
102
+ // If this is a root-level param, like f({ x }), then we need to name
103
+ // it, like $0 or $1, depending on its position.
104
+ return {
105
+ title : 'param' ,
106
+ name : autoName ,
107
+ anonymous : true ,
108
+ type : ( param . typeAnnotation && flowDoctrine ( param ) ) || {
109
+ type : 'NameExpression' ,
110
+ name : 'Object'
111
+ } ,
112
+ properties : _ . flatMap ( param . properties , prop => {
113
+ return paramToDoc ( prop , prefix + autoName ) ;
114
+ } )
115
+ } ;
116
+ } else if ( param . indexed ) {
117
+ // Likewise, if this object pattern sits inside of an ArrayPattern,
118
+ // like [{ foo }], it shouldn't just look like $0.foo, but like $0.0.foo,
119
+ // so make sure it isn't indexed first.
120
+ return {
121
+ title : 'param' ,
122
+ name : prefixedName ,
123
+ anonymous : true ,
124
+ type : ( param . typeAnnotation && flowDoctrine ( param ) ) || {
125
+ type : 'NameExpression' ,
126
+ name : 'Object'
127
+ } ,
128
+ properties : _ . flatMap ( param . properties , prop => {
129
+ return paramToDoc ( prop , prefixedName ) ;
130
+ } )
131
+ } ;
132
+ }
133
+ // If, otherwise, this is nested, we don't really represent it as
134
+ // a parameter in and of itself - we just want its children, and
135
+ // it will be the . in obj.prop
136
+ return _ . flatMap ( param . properties , prop => {
137
+ return paramToDoc ( prop , prefix ) ;
138
+ } ) ;
139
+ // ArrayPattern<Pattern | null>
140
+ case 'ArrayPattern' : // ([a, b, { c }])
141
+ if ( prefix === '' ) {
142
+ return {
143
+ title : 'param' ,
144
+ name : autoName ,
145
+ anonymous : true ,
146
+ type : ( param . typeAnnotation && flowDoctrine ( param ) ) || {
147
+ type : 'NameExpression' ,
148
+ name : 'Array'
149
+ } ,
150
+ // Array destructuring lets you name the elements in the array,
151
+ // but those names don't really make sense within the JSDoc
152
+ // indexing tradition, or have any external meaning. So
153
+ // instead we're going to (immutably) rename the parameters to their
154
+ // indices
155
+ properties : _ . flatMap ( param . elements , ( element , idx ) => {
156
+ var indexedElement = _ . assign ( { } , element , {
157
+ name : String ( idx ) ,
158
+ indexed : true
159
+ } ) ;
160
+ return paramToDoc ( indexedElement , autoName ) ;
161
+ } )
162
+ } ;
163
+ }
164
+ return _ . flatMap ( param . elements , ( element , idx ) => {
165
+ var indexedElement = _ . assign ( { } , element , {
166
+ name : String ( idx )
167
+ } ) ;
168
+ return paramToDoc ( indexedElement , prefix ) ;
169
+ } ) ;
199
170
case 'ObjectProperty' :
200
- return destructuringObjectPropertyToDoc ( param , i , prefix ) ;
201
- case 'RestProperty' :
171
+ return _ . assign ( paramToDoc ( param . value , prefix + '.' + param . key . name ) , {
172
+ name : prefix + '.' + param . key . name
173
+ } ) ;
174
+ case 'RestProperty' : // (a, ...b)
202
175
case 'RestElement' :
203
- return addPrefix ( restParamToDoc ( param ) , prefix ) ;
176
+ let type /*: DoctrineType */ = {
177
+ type : 'RestType'
178
+ } ;
179
+ if ( param . typeAnnotation ) {
180
+ type . expression = flowDoctrine ( param . typeAnnotation . typeAnnotation ) ;
181
+ }
182
+ return {
183
+ title : 'param' ,
184
+ name : param . argument . name ,
185
+ name : prefix ? `${ prefix } .${ param . argument . name } ` : param . argument . name ,
186
+ lineNumber : param . loc . start . line ,
187
+ type
188
+ } ;
204
189
default :
190
+ // (a)
205
191
var newParam /*: CommentTagNamed */ = {
206
192
title : 'param' ,
207
- name : param . name ,
193
+ name : prefix ? prefixedName : param . name ,
208
194
lineNumber : param . loc . start . line
209
195
} ;
210
196
@@ -213,7 +199,7 @@ function paramToDoc(
213
199
newParam . type = flowDoctrine ( param . typeAnnotation . typeAnnotation ) ;
214
200
}
215
201
216
- return addPrefix ( newParam , prefix ) ;
202
+ return newParam ;
217
203
}
218
204
}
219
205
0 commit comments