Skip to content

Commit af0daf8

Browse files
committed
Simplify param inference, update test fixtures. This is focused around Array destructuring: documenting destructured array elements with indices instead of names, because the names are purely internal details
1 parent e0fa855 commit af0daf8

9 files changed

+189
-147
lines changed

lib/infer/params.js

Lines changed: 117 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,19 @@ function inferParams(comment /*: Comment */) {
2828
return comment;
2929
}
3030

31+
var inferredParams = path.node.params.map((param, i) =>
32+
paramToDoc(param, '', i));
33+
34+
var mergedParams = mergeTrees(inferredParams, comment.params);
35+
3136
// Then merge the trees. This is the hard part.
3237
return _.assign(comment, {
33-
params: mergeTrees(
34-
path.node.params.map((param, i) => paramToDoc(param, i, '')),
35-
comment.params
36-
)
38+
params: mergedParams
3739
});
3840
}
3941

4042
// Utility methods ============================================================
4143
//
42-
function addPrefix(doc /*: CommentTagNamed */, prefix) {
43-
return _.assign(doc, {
44-
name: prefix + doc.name
45-
});
46-
}
4744
const PATH_SPLIT_CAPTURING = /(\[])?(\.)/g;
4845

4946
/**
@@ -57,114 +54,6 @@ function mapTags(tags) {
5754
);
5855
}
5956

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-
16857
/**
16958
* Babel parses JavaScript source code and produces an abstract syntax
17059
* tree that includes methods and their arguments. This function takes
@@ -184,27 +73,124 @@ function restParamToDoc(param) /*: CommentTag */ {
18473
*/
18574
function paramToDoc(
18675
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+
19182
switch (param.type) {
19283
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>
194100
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+
});
199170
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)
202175
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+
};
204189
default:
190+
// (a)
205191
var newParam /*: CommentTagNamed */ = {
206192
title: 'param',
207-
name: param.name,
193+
name: prefix ? prefixedName : param.name,
208194
lineNumber: param.loc.start.line
209195
};
210196

@@ -213,7 +199,7 @@ function paramToDoc(
213199
newParam.type = flowDoctrine(param.typeAnnotation.typeAnnotation);
214200
}
215201

216-
return addPrefix(newParam, prefix);
202+
return newParam;
217203
}
218204
}
219205

test/fixture/es6.output-toc.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ Similar, but with an array
1919
**Parameters**
2020

2121
- `$0` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)**
22-
- `$0.a`
23-
- `$0.b`
24-
- `$0.c`
22+
- `$0.0`
23+
- `$0.1`
24+
- `$0.2`
2525

2626
**Examples**
2727

@@ -135,6 +135,6 @@ Regression check for #498
135135

136136
- `array1` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>**
137137
- `array2` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>**
138-
- `compareFunction` **function (a: T, b: T): [boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `(a: T, b: T): boolean => a === b`)
138+
- `compareFunction` **function (a: T, b: T): [boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `(a:T,b:T):boolean=>a===b`)
139139

140140
Returns **[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**

test/fixture/es6.output.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,17 +248,17 @@
248248
"properties": [
249249
{
250250
"title": "param",
251-
"name": "$0.a",
251+
"name": "$0.0",
252252
"lineNumber": 14
253253
},
254254
{
255255
"title": "param",
256-
"name": "$0.b",
256+
"name": "$0.1",
257257
"lineNumber": 14
258258
},
259259
{
260260
"title": "param",
261-
"name": "$0.c",
261+
"name": "$0.2",
262262
"lineNumber": 14
263263
}
264264
]
@@ -2809,7 +2809,7 @@
28092809
}
28102810
}
28112811
},
2812-
"default": "(a: T, b: T): boolean => a === b"
2812+
"default": "(a:T,b:T):boolean=>a===b"
28132813
}
28142814
],
28152815
"properties": [],

test/fixture/es6.output.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ Similar, but with an array
4242
**Parameters**
4343

4444
- `$0` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)**
45-
- `$0.a`
46-
- `$0.b`
47-
- `$0.c`
45+
- `$0.0`
46+
- `$0.1`
47+
- `$0.2`
4848

4949
**Examples**
5050

@@ -158,6 +158,6 @@ Regression check for #498
158158

159159
- `array1` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>**
160160
- `array2` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>**
161-
- `compareFunction` **function (a: T, b: T): [boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `(a: T, b: T): boolean => a === b`)
161+
- `compareFunction` **function (a: T, b: T): [boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `(a:T,b:T):boolean=>a===b`)
162162

163163
Returns **[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**

test/fixture/es6.output.md.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@
379379
"children": [
380380
{
381381
"type": "inlineCode",
382-
"value": "$0.a"
382+
"value": "$0.0"
383383
},
384384
{
385385
"type": "text",
@@ -401,7 +401,7 @@
401401
"children": [
402402
{
403403
"type": "inlineCode",
404-
"value": "$0.b"
404+
"value": "$0.1"
405405
},
406406
{
407407
"type": "text",
@@ -423,7 +423,7 @@
423423
"children": [
424424
{
425425
"type": "inlineCode",
426-
"value": "$0.c"
426+
"value": "$0.2"
427427
},
428428
{
429429
"type": "text",
@@ -2229,7 +2229,7 @@
22292229
},
22302230
{
22312231
"type": "inlineCode",
2232-
"value": "(a: T, b: T): boolean => a === b"
2232+
"value": "(a:T,b:T):boolean=>a===b"
22332233
},
22342234
{
22352235
"type": "text",

0 commit comments

Comments
 (0)