Skip to content

Commit

Permalink
Simplify param inference, update test fixtures. This is focused aroun…
Browse files Browse the repository at this point in the history
…d Array destructuring: documenting destructured array elements with indices instead of names, because the names are purely internal details
  • Loading branch information
tmcw committed Apr 19, 2017
1 parent e0fa855 commit af0daf8
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 147 deletions.
248 changes: 117 additions & 131 deletions lib/infer/params.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,19 @@ function inferParams(comment /*: Comment */) {
return comment;
}

var inferredParams = path.node.params.map((param, i) =>
paramToDoc(param, '', i));

var mergedParams = mergeTrees(inferredParams, comment.params);

// Then merge the trees. This is the hard part.
return _.assign(comment, {
params: mergeTrees(
path.node.params.map((param, i) => paramToDoc(param, i, '')),
comment.params
)
params: mergedParams
});
}

// Utility methods ============================================================
//
function addPrefix(doc /*: CommentTagNamed */, prefix) {
return _.assign(doc, {
name: prefix + doc.name
});
}
const PATH_SPLIT_CAPTURING = /(\[])?(\.)/g;

/**
Expand All @@ -57,114 +54,6 @@ function mapTags(tags) {
);
}

// ___toDoc methods ============================================================
//
// These methods take Babel AST nodes and output equivalent JSDoc parameter tags.
function destructuringObjectParamToDoc(param, i, prefix) /*: CommentTag */ {
return {
title: 'param',
name: '$' + String(i),
anonymous: true,
type: (param.typeAnnotation && flowDoctrine(param)) || {
type: 'NameExpression',
name: 'Object'
},
properties: param.properties.map(prop =>
destructuringPropertyToDoc(prop, i, prefix))
};
}

function destructuringPropertyToDoc(
property,
i /*: number */,
prefix /*: string */
) /*: CommentTag */ {
switch (property.type) {
case 'ObjectProperty':
// Object properties can rename their arguments, like
// function f({ x: y })
// We want to document that as x, not y: y is the internal name.
// So we use the key. In the case where they don't rename,
// key and value are the same.
return paramToDoc(property, i, prefix + '$' + String(i) + '.');
case 'Identifier':
// if the destructuring type is an array, the elements
// in it are identifiers
return paramToDoc(property, i, prefix + '$' + String(i) + '.');
case 'RestProperty':
case 'RestElement':
case 'ObjectPattern':
return paramToDoc(property, i, prefix + '$' + String(i) + '.');
default:
throw new Error(`Unknown property encountered: ${property.type}`);
}
}

function destructuringObjectPropertyToDoc(
param,
i /*: number */,
prefix /*: string */
) /*: CommentTag */ {
return _.assign(paramToDoc(param.value, i, prefix), {
name: prefix + param.key.name
});
}

function destructuringArrayParamToDoc(
param,
i /*: number */,
prefix /*: string */
) /*: CommentTag */ {
return {
title: 'param',
name: '$' + String(i),
anonymous: true,
type: (param.typeAnnotation && flowDoctrine(param)) || {
type: 'NameExpression',
name: 'Array'
},
properties: param.elements.map(element =>
destructuringPropertyToDoc(element, i, prefix))
};
}

/**
* Given a parameter like
*
* function a(b = 1)
*
* Format it as an optional parameter in JSDoc land
*
* @param {Object} param ESTree node
* @returns {Object} JSDoc param
*/
function paramWithDefaultToDoc(param, i) /*: CommentTag */ {
const newParam = paramToDoc(param.left, i, '');

return _.assign(newParam, {
default: generate(param.right).code,
type: {
type: 'OptionalType',
expression: newParam.type
}
});
}

function restParamToDoc(param) /*: CommentTag */ {
let type /*: DoctrineType */ = {
type: 'RestType'
};
if (param.typeAnnotation) {
type.expression = flowDoctrine(param.typeAnnotation.typeAnnotation);
}
return {
title: 'param',
name: param.argument.name,
lineNumber: param.loc.start.line,
type
};
}

/**
* Babel parses JavaScript source code and produces an abstract syntax
* tree that includes methods and their arguments. This function takes
Expand All @@ -184,27 +73,124 @@ function restParamToDoc(param) /*: CommentTag */ {
*/
function paramToDoc(
param,
i /*: number */,
prefix /*: string */
) /*: CommentTag */ {
// ES6 default
prefix /*: string */,
i /*: ?number */
) /*: CommentTag|Array<CommentTag> */ {
const autoName = '$' + String(i);
const prefixedName = prefix + '.' + param.name;

switch (param.type) {
case 'AssignmentPattern': // (a = b)
return addPrefix(paramWithDefaultToDoc(param, i), prefix);
const newAssignmentParam = paramToDoc(param.left, '', i);

if (Array.isArray(newAssignmentParam)) {
throw new Error('Encountered an unexpected parameter type');
}

return _.assign(newAssignmentParam, {
default: generate(param.right, {
compact: true
}).code,
type: {
type: 'OptionalType',
expression: newAssignmentParam.type
}
});
// ObjectPattern <AssignmentProperty | RestElement>
case 'ObjectPattern': // { a }
return destructuringObjectParamToDoc(param, i, prefix);
case 'ArrayPattern':
return destructuringArrayParamToDoc(param, i, prefix);
// TODO: do we need both?
if (prefix === '') {
// If this is a root-level param, like f({ x }), then we need to name
// it, like $0 or $1, depending on its position.
return {
title: 'param',
name: autoName,
anonymous: true,
type: (param.typeAnnotation && flowDoctrine(param)) || {
type: 'NameExpression',
name: 'Object'
},
properties: _.flatMap(param.properties, prop => {
return paramToDoc(prop, prefix + autoName);
})
};
} else if (param.indexed) {
// Likewise, if this object pattern sits inside of an ArrayPattern,
// like [{ foo }], it shouldn't just look like $0.foo, but like $0.0.foo,
// so make sure it isn't indexed first.
return {
title: 'param',
name: prefixedName,
anonymous: true,
type: (param.typeAnnotation && flowDoctrine(param)) || {
type: 'NameExpression',
name: 'Object'
},
properties: _.flatMap(param.properties, prop => {
return paramToDoc(prop, prefixedName);
})
};
}
// If, otherwise, this is nested, we don't really represent it as
// a parameter in and of itself - we just want its children, and
// it will be the . in obj.prop
return _.flatMap(param.properties, prop => {
return paramToDoc(prop, prefix);
});
// ArrayPattern<Pattern | null>
case 'ArrayPattern': // ([a, b, { c }])
if (prefix === '') {
return {
title: 'param',
name: autoName,
anonymous: true,
type: (param.typeAnnotation && flowDoctrine(param)) || {
type: 'NameExpression',
name: 'Array'
},
// Array destructuring lets you name the elements in the array,
// but those names don't really make sense within the JSDoc
// indexing tradition, or have any external meaning. So
// instead we're going to (immutably) rename the parameters to their
// indices
properties: _.flatMap(param.elements, (element, idx) => {
var indexedElement = _.assign({}, element, {
name: String(idx),
indexed: true
});
return paramToDoc(indexedElement, autoName);
})
};
}
return _.flatMap(param.elements, (element, idx) => {
var indexedElement = _.assign({}, element, {
name: String(idx)
});
return paramToDoc(indexedElement, prefix);
});
case 'ObjectProperty':
return destructuringObjectPropertyToDoc(param, i, prefix);
case 'RestProperty':
return _.assign(paramToDoc(param.value, prefix + '.' + param.key.name), {
name: prefix + '.' + param.key.name
});
case 'RestProperty': // (a, ...b)
case 'RestElement':
return addPrefix(restParamToDoc(param), prefix);
let type /*: DoctrineType */ = {
type: 'RestType'
};
if (param.typeAnnotation) {
type.expression = flowDoctrine(param.typeAnnotation.typeAnnotation);
}
return {
title: 'param',
name: param.argument.name,
name: prefix ? `${prefix}.${param.argument.name}` : param.argument.name,
lineNumber: param.loc.start.line,
type
};
default:
// (a)
var newParam /*: CommentTagNamed */ = {
title: 'param',
name: param.name,
name: prefix ? prefixedName : param.name,
lineNumber: param.loc.start.line
};

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

return addPrefix(newParam, prefix);
return newParam;
}
}

Expand Down
8 changes: 4 additions & 4 deletions test/fixture/es6.output-toc.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ Similar, but with an array
**Parameters**

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

**Examples**

Expand Down Expand Up @@ -135,6 +135,6 @@ Regression check for #498

- `array1` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>**
- `array2` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>**
- `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`)
- `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`)

Returns **[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
8 changes: 4 additions & 4 deletions test/fixture/es6.output.json
Original file line number Diff line number Diff line change
Expand Up @@ -248,17 +248,17 @@
"properties": [
{
"title": "param",
"name": "$0.a",
"name": "$0.0",
"lineNumber": 14
},
{
"title": "param",
"name": "$0.b",
"name": "$0.1",
"lineNumber": 14
},
{
"title": "param",
"name": "$0.c",
"name": "$0.2",
"lineNumber": 14
}
]
Expand Down Expand Up @@ -2809,7 +2809,7 @@
}
}
},
"default": "(a: T, b: T): boolean => a === b"
"default": "(a:T,b:T):boolean=>a===b"
}
],
"properties": [],
Expand Down
8 changes: 4 additions & 4 deletions test/fixture/es6.output.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ Similar, but with an array
**Parameters**

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

**Examples**

Expand Down Expand Up @@ -158,6 +158,6 @@ Regression check for #498

- `array1` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>**
- `array2` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>**
- `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`)
- `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`)

Returns **[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
8 changes: 4 additions & 4 deletions test/fixture/es6.output.md.json
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@
"children": [
{
"type": "inlineCode",
"value": "$0.a"
"value": "$0.0"
},
{
"type": "text",
Expand All @@ -401,7 +401,7 @@
"children": [
{
"type": "inlineCode",
"value": "$0.b"
"value": "$0.1"
},
{
"type": "text",
Expand All @@ -423,7 +423,7 @@
"children": [
{
"type": "inlineCode",
"value": "$0.c"
"value": "$0.2"
},
{
"type": "text",
Expand Down Expand Up @@ -2229,7 +2229,7 @@
},
{
"type": "inlineCode",
"value": "(a: T, b: T): boolean => a === b"
"value": "(a:T,b:T):boolean=>a===b"
},
{
"type": "text",
Expand Down
Loading

0 comments on commit af0daf8

Please sign in to comment.