From 7156122a3df2cb5b8e004ff1281c2131f289189c Mon Sep 17 00:00:00 2001 From: Tom Macwright Date: Sat, 15 Apr 2017 01:16:20 -0400 Subject: [PATCH 1/7] refactor(nest): Better nesting implementation This nesting implementation uses a proper recursive tree algorithm Fixes https://github.com/documentationjs/documentation/issues/554 BREAKING CHANGE: referencing inferred destructure params without renaming them, like $0.x, from JSDoc comments will no longer work. To reference them, instead add a param tag to name the destructuring param, and then refer to members of that name. Before: ```js /** * @param {number} $0.x a member of x */ function a({ x }) {} ``` After: ```js /** * @param {Object} options * @param {number} options.x a member of x */ function a({ x }) {} ``` --- circle.yml | 2 +- declarations/comment.js | 43 +- default_theme/section._ | 4 +- index.js | 43 +- lib/infer/params.js | 417 +++++++++++--------- lib/nest.js | 115 +++--- lib/output/markdown_ast.js | 1 + test/fixture/_multi-file-input.json | 3 +- test/fixture/class.output.json | 3 +- test/fixture/es6-class.output.json | 3 +- test/fixture/es6.output-toc.md | 10 +- test/fixture/es6.output.json | 47 ++- test/fixture/es6.output.md | 10 +- test/fixture/es6.output.md.json | 63 ++- test/fixture/inline-link.output.json | 6 +- test/fixture/lends.output.json | 6 +- test/fixture/literal_types.output.json | 3 +- test/fixture/memberedclass.output.json | 3 +- test/fixture/merge-infered-type.output.json | 1 + test/fixture/multisignature.output.json | 3 +- test/fixture/nest_params.output.json | 3 +- test/fixture/params.input.js | 8 +- test/fixture/params.output.json | 193 +++++---- test/fixture/params.output.md | 20 +- test/fixture/params.output.md.json | 131 ++++-- test/fixture/simple-two.output.json | 3 +- test/lib/infer/params.js | 247 ++++++++++++ test/lib/nest.js | 176 +++++---- test/lib/parse.js | 4 +- 29 files changed, 1054 insertions(+), 517 deletions(-) diff --git a/circle.yml b/circle.yml index fe4654099..0465c21b6 100644 --- a/circle.yml +++ b/circle.yml @@ -1,3 +1,3 @@ machine: node: - version: 4 + version: 7 diff --git a/declarations/comment.js b/declarations/comment.js index a876bd6e0..1e12d0c4c 100644 --- a/declarations/comment.js +++ b/declarations/comment.js @@ -58,7 +58,21 @@ declare type CommentContextGitHub = { url: string }; -declare type CommentTag = { +declare type CommentTagBase = { + title: string +}; + +declare type CommentTag = CommentTagBase & { + name?: string, + title: string, + description?: Object, + default?: any, + lineNumber?: number, + type?: DoctrineType, + properties?: Array +}; + +declare type CommentTagNamed = CommentTag & { name?: string, title: string, description?: Object, @@ -88,18 +102,19 @@ declare type Remark = { declare type Access = 'private' | 'public' | 'protected'; declare type Scope = 'instance' | 'static' | 'inner' | 'global'; -declare type Kind = 'class' | - 'constant' | - 'event' | - 'external' | - 'file' | - 'function' | - 'member' | - 'mixin' | - 'module' | - 'namespace' | - 'typedef' | - 'interface'; +declare type Kind = + | 'class' + | 'constant' + | 'event' + | 'external' + | 'file' + | 'function' + | 'member' + | 'mixin' + | 'module' + | 'namespace' + | 'typedef' + | 'interface'; declare type Comment = { errors: Array, @@ -152,4 +167,4 @@ declare type ReducedComment = { name: string, kind: ?Kind, scope?: ?Scope -} +}; diff --git a/default_theme/section._ b/default_theme/section._ index 4ef057fee..a7158640f 100644 --- a/default_theme/section._ +++ b/default_theme/section._ @@ -52,7 +52,7 @@ = <%- param.default %><% } %>) <%= md(param.description, true) %> - <% if (param.properties) { %> + <% if (param.properties && param.properties.length) { %> @@ -93,7 +93,7 @@ <% } %><% if (property.description) { %>: <%= md(property.description, true) %><% } %> - <% if (property.properties) { %> + <% if (property.properties && property.properties.length) { %>
    <% property.properties.forEach(function(property) { %>
  • <%- property.name %> <%= formatType(property.type) %> diff --git a/index.js b/index.js index 6ae6d0987..0c91f4c86 100644 --- a/index.js +++ b/index.js @@ -45,13 +45,10 @@ function pipeline() { }; } - - -function configure(indexes, args)/*: Promise */ { +function configure(indexes, args) /*: Promise */ { let mergedConfig = mergeConfig(args); return mergedConfig.then(config => { - let expandedInputs = expandInputs(indexes, config); return expandedInputs.then(inputs => { @@ -71,8 +68,10 @@ function configure(indexes, args)/*: Promise */ { * @param {Object} config options * @returns {Promise>} promise with results */ -function expandInputs(indexes/*: string|Array */, - config /*: DocumentationConfig */) { +function expandInputs( + indexes /*: string|Array */, + config /*: DocumentationConfig */ +) { // Ensure that indexes is an array of strings indexes = [].concat(indexes); @@ -91,23 +90,24 @@ function buildInternal(inputsAndConfig) { config.access = ['public', 'undefined', 'protected']; } - var parseFn = (config.polyglot) ? polyglot : parseJavaScript; + var parseFn = config.polyglot ? polyglot : parseJavaScript; var buildPipeline = pipeline( inferName, inferAccess(config.inferPrivate), inferAugments, inferKind, + nest, inferParams, inferProperties, inferReturn, inferMembership(), inferType, - nest, config.github && github, - garbageCollect); + garbageCollect + ); - let extractedComments = _.flatMap(inputs, function (sourceFile) { + let extractedComments = _.flatMap(inputs, function(sourceFile) { if (!sourceFile.source) { sourceFile.source = fs.readFileSync(sourceFile.file, 'utf8'); } @@ -115,16 +115,17 @@ function buildInternal(inputsAndConfig) { return parseFn(sourceFile, config).map(buildPipeline); }).filter(Boolean); - return filterAccess(config.access, - hierarchy( - sort(extractedComments, config))); + return filterAccess( + config.access, + hierarchy(sort(extractedComments, config)) + ); } function lintInternal(inputsAndConfig) { let inputs = inputsAndConfig.inputs; let config = inputsAndConfig.config; - let parseFn = (config.polyglot) ? polyglot : parseJavaScript; + let parseFn = config.polyglot ? polyglot : parseJavaScript; let lintPipeline = pipeline( lintComments, @@ -137,7 +138,8 @@ function lintInternal(inputsAndConfig) { inferReturn, inferMembership(), inferType, - nest); + nest + ); let extractedComments = _.flatMap(inputs, sourceFile => { if (!sourceFile.source) { @@ -183,8 +185,7 @@ function lintInternal(inputsAndConfig) { * } * }); */ -let lint = (indexes, args) => configure(indexes, args) - .then(lintInternal); +let lint = (indexes, args) => configure(indexes, args).then(lintInternal); /** * Generate JavaScript documentation as a list of parsed JSDoc @@ -227,8 +228,7 @@ let lint = (indexes, args) => configure(indexes, args) * // any other kind of code data. * }); */ -let build = (indexes, args) => configure(indexes, args) - .then(buildInternal); +let build = (indexes, args) => configure(indexes, args).then(buildInternal); /** * Documentation's formats are modular methods that take comments @@ -240,9 +240,8 @@ let build = (indexes, args) => configure(indexes, args) var formats = { html: require('./lib/output/html'), md: require('./lib/output/markdown'), - remark: (comments/*: Array */, config/*: DocumentationConfig */) => - markdownAST(comments, config) - .then(res => JSON.stringify(res, null, 2)), + remark: (comments /*: Array */, config /*: DocumentationConfig */) => + markdownAST(comments, config).then(res => JSON.stringify(res, null, 2)), json: require('./lib/output/json') }; diff --git a/lib/infer/params.js b/lib/infer/params.js index ffa430034..7de521778 100644 --- a/lib/infer/params.js +++ b/lib/infer/params.js @@ -1,15 +1,89 @@ 'use strict'; /* @flow */ -var t = require('babel-types'), - findTarget = require('./finders').findTarget, - flowDoctrine = require('../flow_doctrine'); +const t = require('babel-types'); +const generate = require('babel-generator').default; +const _ = require('lodash'); +const findTarget = require('./finders').findTarget; +const flowDoctrine = require('../flow_doctrine'); +const util = require('util'); +const debuglog = util.debuglog('infer'); -function addPrefix(doc, prefix) { - if (!Array.isArray(doc) && doc.name) { - doc.name = prefix + doc.name; +// TODO: use a constant +const PATH_SPLIT_CAPTURING = /(\[])?(\.)/g; + +function addPrefix(doc /*: CommentTagNamed */, prefix) { + return _.assign(doc, { + name: prefix + doc.name + }); +} + +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}`); } - return doc; +} + +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)) + }; } /** @@ -22,38 +96,31 @@ function addPrefix(doc, prefix) { * @param {Object} param ESTree node * @returns {Object} JSDoc param */ -function paramWithDefaultToDoc( - param, - comment, - i -) /*: CommentTag | Array */ { - var newParam = paramToDoc(param.left, comment, i, ''); +function paramWithDefaultToDoc(param, i) /*: CommentTag */ { + const newParam = paramToDoc(param.left, i, ''); - var defaultValue = comment.context.code.substring( - param.right.start, - param.right.end - ); + return _.assign(newParam, { + default: generate(param.right).code, + type: { + type: 'OptionalType', + expression: newParam.type + } + }); +} - // this is a destructuring parameter with defaults - if (Array.isArray(newParam)) { - newParam[0].default = defaultValue; - return newParam; +function restParamToDoc(param) /*: CommentTag */ { + let type /*: DoctrineType */ = { + type: 'RestType' + }; + if (param.typeAnnotation) { + type.expression = flowDoctrine(param.typeAnnotation.typeAnnotation); } - - var optionalParam /*: CommentTag */ = { + return { title: 'param', - name: newParam.name, - default: defaultValue + name: param.argument.name, + lineNumber: param.loc.start.line, + type }; - - if (newParam.type) { - optionalParam.type = { - type: 'OptionalType', - expression: newParam.type - }; - } - - return optionalParam; } /** @@ -69,128 +136,43 @@ function paramWithDefaultToDoc( * * @private * @param {Object} param the abstract syntax tree of the parameter in JavaScript - * @param {Object} comment the full comment object * @param {number} i the number of this parameter, in argument order * @param {string} prefix of the comment, if it is nested, like in the case of destructuring * @returns {Object} parameter with inference. */ function paramToDoc( param, - comment /*: Comment */, i /*: number */, prefix /*: string */ -) /*: Array | CommentTag */ { - function destructuringPropertyToDoc( - property - ) /*: Array | CommentTag */ { - if (property.type === 'ObjectProperty') { - return paramToDoc( - property.value, - comment, - i, - prefix + '$' + String(i) + '.' - ); - } else if (property.type === 'Identifier') { - // if the destructuring type is an array, the elements - // in it are identifiers - return paramToDoc(property, comment, i, prefix + '$' + String(i) + '.'); - } else if (property.type === 'RestProperty') { - return paramToDoc(property, comment, i, prefix + '$' + String(i) + '.'); - } else if (property.type === 'RestElement') { - return paramToDoc(property, comment, i, prefix + '$' + String(i) + '.'); - } - throw new Error(`Unknown property encountered: ${property.type}`); - } - - function destructuringObjectParamToDoc(param) /*: Array */ { - return [ - { +) /*: CommentTag */ { + // ES6 default + switch (param.type) { + case 'AssignmentPattern': // (a = b) + return addPrefix(paramWithDefaultToDoc(param, i), prefix); + case 'ObjectPattern': // { a } + return destructuringObjectParamToDoc(param, i, prefix); + case 'ArrayPattern': + return destructuringArrayParamToDoc(param, i, prefix); + // TODO: do we need both? + case 'ObjectProperty': + return destructuringObjectPropertyToDoc(param, i, prefix); + case 'RestProperty': + case 'RestElement': + return addPrefix(restParamToDoc(param), prefix); + default: + var newParam /*: CommentTagNamed */ = { title: 'param', - name: '$' + String(i), - type: flowDoctrine(param) || { - type: 'NameExpression', - name: 'Object' - } - } - ].concat(param.properties.map(destructuringPropertyToDoc)); - } + name: param.name, + lineNumber: param.loc.start.line + }; - function destructuringArrayParamToDoc(param) /*: Array */ { - return [ - { - title: 'param', - name: '$' + String(i), - type: flowDoctrine(param) || { - type: 'NameExpression', - name: 'Array' - } + // Flow/TS annotations + if (param.typeAnnotation && param.typeAnnotation.typeAnnotation) { + newParam.type = flowDoctrine(param.typeAnnotation.typeAnnotation); } - ].concat(param.elements.map(destructuringPropertyToDoc)); - } - - function restParamToDoc(param) /*: CommentTag */ { - let type /*: DoctrineType */ = { - type: 'RestType' - }; - if (param.typeAnnotation) { - type.expression = flowDoctrine(param.typeAnnotation.typeAnnotation); - } - var newParam = { - title: 'param', - name: param.argument.name, - lineNumber: param.loc.start.line, - type - }; - return newParam; - } - - // ES6 default - if (param.type === 'AssignmentPattern') { - return addPrefix(paramWithDefaultToDoc(param, comment, i), prefix); - } - - if (param.type === 'ObjectPattern') { - return destructuringObjectParamToDoc(param); - } - - if (param.type === 'ArrayPattern') { - return destructuringArrayParamToDoc(param); - } - - if (param.type === 'RestProperty' || param.type === 'RestElement') { - return addPrefix(restParamToDoc(param), prefix); - } - - var newParam /*: CommentTag */ = { - title: 'param', - name: param.name, - lineNumber: param.loc.start.line - }; - // Flow/TS annotations - if (param.typeAnnotation && param.typeAnnotation.typeAnnotation) { - newParam.type = flowDoctrine(param.typeAnnotation.typeAnnotation); + return addPrefix(newParam, prefix); } - - return addPrefix(newParam, prefix); -} - -function insertBeforeDependents(comment, comments) { - var dependentNamePrefix = comment.name + '.'; - for ( - var insertionIndex = 0; - insertionIndex < comments.length; - insertionIndex++ - ) { - let commentName = comments[insertionIndex].name; - if (commentName && commentName.indexOf(dependentNamePrefix) === 0) { - break; - } - } - return comments - .slice(0, insertionIndex) - .concat(comment) - .concat(comments.slice(insertionIndex)); } /** @@ -212,49 +194,122 @@ function inferParams(comment /*: Comment */) { return comment; } - // Ensure that explicitly specified parameters are not overridden - // by inferred parameters - var existingParams = {}; - comment.params.forEach(function(param) { - if (typeof param.name === 'string') { - existingParams[param.name] = param; - } + // 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 + ) }); +} - var paramOrder = {}; - var i = 0; +/** + * Recurse through a potentially nested parameter tag, + * replacing the auto-generated name, like $0, with an explicit + * name provided from a JSDoc comment + */ +function renameTree(node, explicitName) { + var parts = node.name.split(PATH_SPLIT_CAPTURING); + parts[0] = explicitName; + node.name = parts.join(''); + if (node.properties) { + node.properties.forEach(property => renameTree(property, explicitName)); + } +} - path.node.params - .reduce( - function(params, param, i) { - return params.concat(paramToDoc(param, comment, i, '')); - }, - [] - ) - .forEach(function(doc) { - if (!existingParams.hasOwnProperty(doc.name)) { - // This type is not explicitly documented - comment.params = insertBeforeDependents(doc, comment.params); - } else if (!existingParams[doc.name].type) { - // This param has a description, but potentially it can - // be have an inferred type. Infer its type without - // dropping the description. - if (doc.type) { - existingParams[doc.name].type = doc.type; - } - } else if ( - existingParams[doc.name].type.type !== 'OptionalType' && doc.default - ) { - existingParams[doc.name].type = { - type: 'OptionalType', - expression: existingParams[doc.name].type, - default: doc.default - }; +var mapTags = tags => new Map(tags.map(tag => [tag.name, tag])); + +function mergeTrees(inferred, explicit) { + // The first order of business is ensuring that the root types are specified + // in the right order. For the order of arguments, the inferred reality + // is the ground-truth: a function like + // function addThem(a, b, c) {} + // Should always see (a, b, c) in that order + + // First, if all parameters are specified, allow explicit names to apply + // to destructuring parameters, which do not have inferred names. This is + // _only_ enabled in the case in which all parameters are specified explicitly + if (inferred.length === explicit.length) { + for (var i = 0; i < inferred.length; i++) { + if (inferred[i].anonymous === true) { + renameTree(inferred[i], explicit[i].name); } - paramOrder[doc.name] = i++; - }); + } + } + + return mergeTopNodes(inferred, explicit); +} - return comment; +function mergeTopNodes(inferred, explicit) { + const mapExplicit = mapTags(explicit); + const inferredNames = new Set(inferred.map(tag => tag.name)); + const explicitTagsWithoutInference = explicit.filter( + tag => !inferredNames.has(tag.name) + ); + + if (explicitTagsWithoutInference.length) { + debuglog( + `${explicitTagsWithoutInference.length} tags were specified but didn't match ` + + `inferred information ${explicitTagsWithoutInference + .map(t => t.name) + .join(', ')}` + ); + } + + return inferred + .map(inferredTag => { + const explicitTag = mapExplicit.get(inferredTag.name); + return explicitTag ? combineTags(inferredTag, explicitTag) : inferredTag; + }) + .concat(explicitTagsWithoutInference); +} + +// This method is used for _non-root_ properties only - we use mergeTopNodes +// for root properties, which strictly requires inferred only. In this case, +// we combine all tags: +// - inferred & explicit +// - explicit only +// - inferred only +function mergeNodes(inferred, explicit) { + const intersection = _.intersectionBy(inferred, explicit, tag => tag.name); + const explicitOnly = _.differenceBy(explicit, inferred, tag => tag.name); + const inferredOnly = _.differenceBy(inferred, explicit, tag => tag.name); + const mapExplicit = mapTags(explicit); + + return intersection + .map(inferredTag => { + const explicitTag = mapExplicit.get(inferredTag.name); + return explicitTag ? combineTags(inferredTag, explicitTag) : inferredTag; + }) + .concat(explicitOnly) + .concat(inferredOnly); +} + +function combineTags(inferredTag, explicitTag) { + let type = explicitTag.type; + var defaultValue; + if (!explicitTag.type) { + type = inferredTag.type; + } else if (explicitTag.type.type !== 'OptionalType' && inferredTag.default) { + type = { + type: 'OptionalType', + expression: explicitTag.type + }; + defaultValue = inferredTag.default; + } + + return _.assign( + explicitTag, + { + properties: mergeNodes( + inferredTag.properties || [], + explicitTag.properties || [] + ), + type + }, + defaultValue ? { default: defaultValue } : {} + ); } module.exports = inferParams; +module.exports.mergeTrees = mergeTrees; diff --git a/lib/nest.js b/lib/nest.js index 753adf6e3..4cc0c8559 100644 --- a/lib/nest.js +++ b/lib/nest.js @@ -1,9 +1,35 @@ /* @flow */ 'use strict'; +var _ = require('lodash'); + +const PATH_SPLIT = /(?:\[])?\./g; + +function rejectUnnamedTags( + tags /*: Array */ +) /*: Array */ { + return tags.filter(tag => typeof tag.name === 'string'); +} + +var tagDepth = tag => tag.name.split(PATH_SPLIT).length; + /** * Nest nestable tags, like param and property, into nested * arrays that are suitable for output. + * Okay, so we're building a tree of comments, with the tag.name + * being the indexer. We sort by depth, so that we add each + * level of the tree incrementally, and throw if we run against + * a node that doesn't have a parent. + * + * foo.abe + * foo.bar.baz + * foo.bar.a + * foo.bar[].bax + * + * foo -> .abe + * \-> .bar -> .baz + * \-> .a + * \-> [].baz * * @private * @param {Object} comment a comment with tags @@ -11,52 +37,50 @@ * @param {string} target the tag to nest into * @returns {Object} nested comment */ -function nestTag( - comment /*: Comment */, - tagTitle /*: string */, - target /*: string */ -) { - if (!comment[target]) { - return comment; - } +var nestTag = ( + tags /*: Array */ + // Use lodash here both for brevity and also because, unlike JavaScript's + // sort, it's stable. +) => + _.sortBy(rejectUnnamedTags(tags), tagDepth).reduce( + (memo, tag) => { + function insertTag(node, parts) { + // The 'done' case: we're at parts.length === 1, + // this is where the node should be placed. We reliably + // get to this case because the recursive method + // is always passed parts.slice(1) + if (parts.length === 1) { + _.assign(node, { + properties: (node.properties || []).concat(tag) + }); + } else { + // The recursive case: try to find the child that owns + // this tag. + let child = node.properties && + node.properties.find( + property => parts[0] === _.last(property.name.split(PATH_SPLIT)) + ); - var result = [], index = {}; + if (!child) { + if (tag.name.match(/^(\$\d+)/)) { + throw new Error( + `Parent of ${tag.name} not found. To document a destructuring\n` + + `type, add a @param tag in its position to specify the name of the\n` + + `destructured parameter` + ); + } + throw new Error(`Parent of ${tag.name} not found`); + } - comment[target].forEach(tag => { - var tagName = tag.name; - if (tagName) { - index[tagName] = tag; - var parts = tagName - .split(/(\[\])?\./) - .filter(part => part && part !== '[]'); - if (parts.length > 1) { - var parent = index[parts.slice(0, -1).join('.')]; - if (parent === undefined) { - comment.errors.push({ - message: '@' + - tagTitle + - ' ' + - tag.name + - "'s parent " + - parts[0] + - ' not found', - commentLineNumber: tag.lineNumber - }); - result.push(tag); - return; + insertTag(child, parts.slice(1)); } - parent.properties = parent.properties || []; - parent.properties.push(tag); - } else { - result.push(tag); } - } - }); - comment[target] = result; - - return comment; -} + insertTag(memo, tag.name.split(PATH_SPLIT)); + return memo; + }, + { properties: [] } + ).properties; /** * Nests @@ -70,8 +94,11 @@ function nestTag( * @param {Object} comment input comment * @return {Object} nested comment */ -function nest(comment /*: Comment*/) { - return nestTag(nestTag(comment, 'param', 'params'), 'property', 'properties'); -} +var nest = (comment /*: Comment*/) => + _.assign(comment, { + params: nestTag(comment.params), + properties: nestTag(comment.properties) + }); module.exports = nest; +module.exports.nestTag = nestTag; diff --git a/lib/output/markdown_ast.js b/lib/output/markdown_ast.js index 29e0537a3..2a7f10bec 100644 --- a/lib/output/markdown_ast.js +++ b/lib/output/markdown_ast.js @@ -72,6 +72,7 @@ function buildMarkdownAST( } function paramList(params /*: Array */) { + if (params.length === 0) return []; return u( 'list', { ordered: false }, diff --git a/test/fixture/_multi-file-input.json b/test/fixture/_multi-file-input.json index 11a72d624..cf00595cf 100644 --- a/test/fixture/_multi-file-input.json +++ b/test/fixture/_multi-file-input.json @@ -167,7 +167,8 @@ "type": { "type": "NameExpression", "name": "Number" - } + }, + "properties": [] } ], "properties": [], diff --git a/test/fixture/class.output.json b/test/fixture/class.output.json index 37f1d9b70..d909a684e 100644 --- a/test/fixture/class.output.json +++ b/test/fixture/class.output.json @@ -329,7 +329,8 @@ "type": { "type": "NameExpression", "name": "boolean" - } + }, + "properties": [] } ], "properties": [], diff --git a/test/fixture/es6-class.output.json b/test/fixture/es6-class.output.json index 78ce308f3..45aaee754 100644 --- a/test/fixture/es6-class.output.json +++ b/test/fixture/es6-class.output.json @@ -295,7 +295,8 @@ "type": { "type": "NameExpression", "name": "string" - } + }, + "properties": [] } ], "properties": [], diff --git a/test/fixture/es6.output-toc.md b/test/fixture/es6.output-toc.md index 95a3c2c68..7e731557a 100644 --- a/test/fixture/es6.output-toc.md +++ b/test/fixture/es6.output-toc.md @@ -7,9 +7,9 @@ have any parameter descriptions. **Parameters** -- `$0` **any** (optional, default `{}`) - - `$0.phoneNumbers` (optional, default `[]`) - - `$0.emailAddresses` (optional, default `[]`) +- `$0` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** (optional, default `{}`) + - `$0.phoneNumbers` **any?** (optional, default `[]`) + - `$0.emailAddresses` **any?** (optional, default `[]`) - `$0.params` **...any** ## destructure @@ -18,7 +18,7 @@ Similar, but with an array **Parameters** -- `$0` **any** +- `$0` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** - `$0.a` - `$0.b` - `$0.c` @@ -113,7 +113,7 @@ This tests our support of optional parameters in ES6 **Parameters** -- `foo` (optional, default `'bar'`) +- `foo` **any?** (optional, default `'bar'`) ## iAmProtected diff --git a/test/fixture/es6.output.json b/test/fixture/es6.output.json index 7ada1a342..a63054ec4 100644 --- a/test/fixture/es6.output.json +++ b/test/fixture/es6.output.json @@ -86,20 +86,32 @@ { "title": "param", "name": "$0", + "anonymous": true, "type": { - "type": "AllLiteral" + "type": "OptionalType", + "expression": { + "type": "NameExpression", + "name": "Object" + } }, - "default": "{}", "properties": [ { "title": "param", "name": "$0.phoneNumbers", - "default": "[]" + "lineNumber": 6, + "default": "[]", + "type": { + "type": "OptionalType" + } }, { "title": "param", "name": "$0.emailAddresses", - "default": "[]" + "lineNumber": 6, + "default": "[]", + "type": { + "type": "OptionalType" + } }, { "title": "param", @@ -109,7 +121,8 @@ "type": "RestType" } } - ] + ], + "default": "{}" } ], "properties": [], @@ -227,8 +240,10 @@ { "title": "param", "name": "$0", + "anonymous": true, "type": { - "type": "AllLiteral" + "type": "NameExpression", + "name": "Array" }, "properties": [ { @@ -448,7 +463,8 @@ "name": "Number" } ] - } + }, + "properties": [] }, { "title": "param", @@ -1069,7 +1085,8 @@ "type": { "type": "NameExpression", "name": "number" - } + }, + "properties": [] }, { "title": "param", @@ -1130,7 +1147,8 @@ "type": { "type": "NameExpression", "name": "number" - } + }, + "properties": [] } ], "properties": [], @@ -2299,7 +2317,11 @@ { "title": "param", "name": "foo", - "default": "'bar'" + "lineNumber": 114, + "default": "'bar'", + "type": { + "type": "OptionalType" + } } ], "properties": [], @@ -2761,7 +2783,7 @@ { "title": "param", "name": "compareFunction", - "default": "(a: T, b: T): boolean => a === b", + "lineNumber": 153, "type": { "type": "OptionalType", "expression": { @@ -2789,7 +2811,8 @@ "name": "boolean" } } - } + }, + "default": "(a: T, b: T): boolean => a === b" } ], "properties": [], diff --git a/test/fixture/es6.output.md b/test/fixture/es6.output.md index 985716788..84c9e963e 100644 --- a/test/fixture/es6.output.md +++ b/test/fixture/es6.output.md @@ -30,9 +30,9 @@ have any parameter descriptions. **Parameters** -- `$0` **any** (optional, default `{}`) - - `$0.phoneNumbers` (optional, default `[]`) - - `$0.emailAddresses` (optional, default `[]`) +- `$0` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** (optional, default `{}`) + - `$0.phoneNumbers` **any?** (optional, default `[]`) + - `$0.emailAddresses` **any?** (optional, default `[]`) - `$0.params` **...any** ## destructure @@ -41,7 +41,7 @@ Similar, but with an array **Parameters** -- `$0` **any** +- `$0` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** - `$0.a` - `$0.b` - `$0.c` @@ -136,7 +136,7 @@ This tests our support of optional parameters in ES6 **Parameters** -- `foo` (optional, default `'bar'`) +- `foo` **any?** (optional, default `'bar'`) ## iAmProtected diff --git a/test/fixture/es6.output.md.json b/test/fixture/es6.output.md.json index 7826d97d5..74617b58a 100644 --- a/test/fixture/es6.output.md.json +++ b/test/fixture/es6.output.md.json @@ -84,9 +84,20 @@ { "type": "strong", "children": [ + { + "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object", + "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object", + "type": "link", + "children": [ + { + "type": "text", + "value": "Object" + } + ] + }, { "type": "text", - "value": "any" + "value": "?" } ] }, @@ -131,6 +142,19 @@ "type": "text", "value": " " }, + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "any" + }, + { + "type": "text", + "value": "?" + } + ] + }, { "type": "text", "value": " " @@ -170,6 +194,19 @@ "type": "text", "value": " " }, + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "any" + }, + { + "type": "text", + "value": "?" + } + ] + }, { "type": "text", "value": " " @@ -312,8 +349,15 @@ "type": "strong", "children": [ { - "type": "text", - "value": "any" + "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array", + "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array", + "type": "link", + "children": [ + { + "type": "text", + "value": "Array" + } + ] } ] }, @@ -1773,6 +1817,19 @@ "type": "text", "value": " " }, + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "any" + }, + { + "type": "text", + "value": "?" + } + ] + }, { "type": "text", "value": " " diff --git a/test/fixture/inline-link.output.json b/test/fixture/inline-link.output.json index 95ae461d5..060654315 100644 --- a/test/fixture/inline-link.output.json +++ b/test/fixture/inline-link.output.json @@ -158,7 +158,8 @@ "type": { "type": "NameExpression", "name": "number" - } + }, + "properties": [] } ], "properties": [], @@ -581,7 +582,8 @@ "type": { "type": "NameExpression", "name": "number" - } + }, + "properties": [] } ], "properties": [], diff --git a/test/fixture/lends.output.json b/test/fixture/lends.output.json index 4a231651f..3fc2c210f 100644 --- a/test/fixture/lends.output.json +++ b/test/fixture/lends.output.json @@ -272,7 +272,8 @@ "type": { "type": "NameExpression", "name": "string" - } + }, + "properties": [] } ], "properties": [], @@ -523,7 +524,8 @@ "type": { "type": "NameExpression", "name": "string" - } + }, + "properties": [] } ], "properties": [], diff --git a/test/fixture/literal_types.output.json b/test/fixture/literal_types.output.json index 858b92501..5300b7035 100644 --- a/test/fixture/literal_types.output.json +++ b/test/fixture/literal_types.output.json @@ -96,7 +96,8 @@ "value": 3.14 } ] - } + }, + "properties": [] } ], "properties": [], diff --git a/test/fixture/memberedclass.output.json b/test/fixture/memberedclass.output.json index a817352c9..6d125b531 100644 --- a/test/fixture/memberedclass.output.json +++ b/test/fixture/memberedclass.output.json @@ -268,7 +268,8 @@ "type": { "type": "NameExpression", "name": "boolean" - } + }, + "properties": [] } ], "properties": [], diff --git a/test/fixture/merge-infered-type.output.json b/test/fixture/merge-infered-type.output.json index 61f6b15c2..b424e90b9 100644 --- a/test/fixture/merge-infered-type.output.json +++ b/test/fixture/merge-infered-type.output.json @@ -183,6 +183,7 @@ } } }, + "properties": [], "type": { "type": "NameExpression", "name": "number" diff --git a/test/fixture/multisignature.output.json b/test/fixture/multisignature.output.json index ba7426e9a..4a22e59c0 100644 --- a/test/fixture/multisignature.output.json +++ b/test/fixture/multisignature.output.json @@ -335,7 +335,8 @@ "type": { "type": "NameExpression", "name": "Date" - } + }, + "properties": [] } ], "properties": [], diff --git a/test/fixture/nest_params.output.json b/test/fixture/nest_params.output.json index 70a9cf890..a444a5767 100644 --- a/test/fixture/nest_params.output.json +++ b/test/fixture/nest_params.output.json @@ -339,7 +339,8 @@ "name": "string" } }, - "default": "minion" + "default": "minion", + "properties": [] } ], "properties": [], diff --git a/test/fixture/params.input.js b/test/fixture/params.input.js index cea9becdf..c9522355c 100644 --- a/test/fixture/params.input.js +++ b/test/fixture/params.input.js @@ -8,7 +8,8 @@ function addThem(a, b, c, { d, e, f }) { /** * This method has partially inferred params - * @param {String} $0.fishes number of kinds of fish + * @param {Object} options + * @param {String} options.fishes number of kinds of fish */ function fishesAndFoxes({ fishes, foxes }) { return fishes + foxes; @@ -99,8 +100,9 @@ function foo(address) { * This tests our support for iterator rest inside an * iterator destructure (RestElement) * - * @param {any} $0.x head of iterator - * @param {any[]} ...$0.xs body of iterator + * @param {Array} input + * @param {any} input.x head of iterator + * @param {any[]} ...input.xs body of iterator * * @returns {any[]} rotated such that the last element was the first */ diff --git a/test/fixture/params.output.json b/test/fixture/params.output.json index 01241aec6..997f3c05e 100644 --- a/test/fixture/params.output.json +++ b/test/fixture/params.output.json @@ -90,6 +90,11 @@ "errors": [], "examples": [], "params": [ + { + "title": "param", + "name": "a", + "lineNumber": 5 + }, { "title": "param", "name": "b", @@ -149,12 +154,8 @@ "type": { "type": "NameExpression", "name": "number" - } - }, - { - "title": "param", - "name": "a", - "lineNumber": 5 + }, + "properties": [] }, { "title": "param", @@ -164,8 +165,10 @@ { "title": "param", "name": "$3", + "anonymous": true, "type": { - "type": "AllLiteral" + "type": "NameExpression", + "name": "Object" }, "properties": [ { @@ -264,13 +267,23 @@ "tags": [ { "title": "param", - "description": "number of kinds of fish", + "description": null, "lineNumber": 2, + "type": { + "type": "NameExpression", + "name": "Object" + }, + "name": "options" + }, + { + "title": "param", + "description": "number of kinds of fish", + "lineNumber": 3, "type": { "type": "NameExpression", "name": "String" }, - "name": "$0.fishes" + "name": "options.fishes" } ], "loc": { @@ -279,18 +292,18 @@ "column": 0 }, "end": { - "line": 12, + "line": 13, "column": 3 } }, "context": { "loc": { "start": { - "line": 13, + "line": 14, "column": 0 }, "end": { - "line": 15, + "line": 16, "column": 1 } } @@ -301,15 +314,17 @@ "params": [ { "title": "param", - "name": "$0", + "name": "options", + "lineNumber": 2, "type": { - "type": "AllLiteral" + "type": "NameExpression", + "name": "Object" }, "properties": [ { "title": "param", - "name": "$0.fishes", - "lineNumber": 2, + "name": "options.fishes", + "lineNumber": 3, "description": { "type": "root", "children": [ @@ -365,12 +380,13 @@ "type": { "type": "NameExpression", "name": "String" - } + }, + "properties": [] }, { "title": "param", - "name": "$0.foxes", - "lineNumber": 13 + "name": "options.foxes", + "lineNumber": 14 } ] } @@ -464,22 +480,22 @@ ], "loc": { "start": { - "line": 17, + "line": 18, "column": 0 }, "end": { - "line": 20, + "line": 21, "column": 3 } }, "context": { "loc": { "start": { - "line": 21, + "line": 22, "column": 0 }, "end": { - "line": 23, + "line": 24, "column": 1 } } @@ -497,9 +513,10 @@ "expression": { "type": "NameExpression", "name": "number" - }, - "default": "2" - } + } + }, + "properties": [], + "default": "2" } ], "properties": [], @@ -580,22 +597,22 @@ "tags": [], "loc": { "start": { - "line": 25, + "line": 26, "column": 0 }, "end": { - "line": 27, + "line": 28, "column": 3 } }, "context": { "loc": { "start": { - "line": 28, + "line": 29, "column": 0 }, "end": { - "line": 34, + "line": 35, "column": 1 } } @@ -682,22 +699,22 @@ ], "loc": { "start": { - "line": 29, + "line": 30, "column": 2 }, "end": { - "line": 32, + "line": 33, "column": 5 } }, "context": { "loc": { "start": { - "line": 33, + "line": 34, "column": 2 }, "end": { - "line": 33, + "line": 34, "column": 14 } } @@ -765,7 +782,8 @@ "type": { "type": "NameExpression", "name": "number" - } + }, + "properties": [] } ], "properties": [], @@ -865,22 +883,22 @@ "tags": [], "loc": { "start": { - "line": 36, + "line": 37, "column": 0 }, "end": { - "line": 38, + "line": 39, "column": 3 } }, "context": { "loc": { "start": { - "line": 39, + "line": 40, "column": 0 }, "end": { - "line": 46, + "line": 47, "column": 2 } } @@ -957,22 +975,22 @@ "tags": [], "loc": { "start": { - "line": 40, + "line": 41, "column": 2 }, "end": { - "line": 42, + "line": 43, "column": 5 } }, "context": { "loc": { "start": { - "line": 43, + "line": 44, "column": 2 }, "end": { - "line": 45, + "line": 46, "column": 3 } } @@ -984,7 +1002,7 @@ { "title": "param", "name": "x", - "lineNumber": 43 + "lineNumber": 44 } ], "properties": [], @@ -1180,22 +1198,22 @@ ], "loc": { "start": { - "line": 48, + "line": 49, "column": 0 }, "end": { - "line": 59, + "line": 60, "column": 3 } }, "context": { "loc": { "start": { - "line": 60, + "line": 61, "column": 0 }, "end": { - "line": 60, + "line": 61, "column": 22 } } @@ -1658,22 +1676,22 @@ ], "loc": { "start": { - "line": 62, + "line": 63, "column": 0 }, "end": { - "line": 73, + "line": 74, "column": 3 } }, "context": { "loc": { "start": { - "line": 74, + "line": 75, "column": 0 }, "end": { - "line": 76, + "line": 77, "column": 1 } } @@ -2118,22 +2136,22 @@ ], "loc": { "start": { - "line": 78, + "line": 79, "column": 0 }, "end": { - "line": 85, + "line": 86, "column": 3 } }, "context": { "loc": { "start": { - "line": 86, + "line": 87, "column": 0 }, "end": { - "line": 86, + "line": 87, "column": 37 } } @@ -2203,9 +2221,10 @@ "expression": { "type": "NameExpression", "name": "number" - }, - "default": "123" - } + } + }, + "properties": [], + "default": "123" } ], "properties": [], @@ -2358,22 +2377,22 @@ ], "loc": { "start": { - "line": 88, + "line": 89, "column": 0 }, "end": { - "line": 93, + "line": 94, "column": 3 } }, "context": { "loc": { "start": { - "line": 94, + "line": 95, "column": 0 }, "end": { - "line": 96, + "line": 97, "column": 1 } } @@ -2437,7 +2456,8 @@ "offset": 22 } } - } + }, + "properties": [] } ], "properties": [], @@ -2522,18 +2542,28 @@ "tags": [ { "title": "param", - "description": "head of iterator", + "description": null, "lineNumber": 4, "type": { "type": "NameExpression", - "name": "any" + "name": "Array" }, - "name": "$0.x" + "name": "input" }, { "title": "param", - "description": "...$0.xs body of iterator", + "description": "head of iterator", "lineNumber": 5, + "type": { + "type": "NameExpression", + "name": "any" + }, + "name": "input.x" + }, + { + "title": "param", + "description": "...input.xs body of iterator", + "lineNumber": 6, "type": { "type": "TypeApplication", "expression": { @@ -2555,7 +2585,7 @@ { "title": "returns", "description": "rotated such that the last element was the first", - "lineNumber": 7, + "lineNumber": 8, "type": { "type": "TypeApplication", "expression": { @@ -2573,22 +2603,22 @@ ], "loc": { "start": { - "line": 98, + "line": 99, "column": 0 }, "end": { - "line": 106, + "line": 108, "column": 3 } }, "context": { "loc": { "start": { - "line": 107, + "line": 109, "column": 0 }, "end": { - "line": 109, + "line": 111, "column": 1 } } @@ -2603,15 +2633,17 @@ "params": [ { "title": "param", - "name": "$0", + "name": "input", + "lineNumber": 4, "type": { - "type": "AllLiteral" + "type": "NameExpression", + "name": "Array" }, "properties": [ { "title": "param", - "name": "$0.x", - "lineNumber": 4, + "name": "input.x", + "lineNumber": 5, "description": { "type": "root", "children": [ @@ -2667,12 +2699,13 @@ "type": { "type": "NameExpression", "name": "any" - } + }, + "properties": [] }, { "title": "param", - "name": "$0.xs", - "lineNumber": 107, + "name": "input.xs", + "lineNumber": 109, "type": { "type": "RestType" } diff --git a/test/fixture/params.output.md b/test/fixture/params.output.md index c9df3621a..66737b81b 100644 --- a/test/fixture/params.output.md +++ b/test/fixture/params.output.md @@ -21,10 +21,10 @@ This function returns the number one. **Parameters** -- `b` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** the second param - `a` +- `b` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** the second param - `c` -- `$3` **any** +- `$3` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** - `$3.d` - `$3.e` - `$3.f` @@ -35,9 +35,9 @@ This method has partially inferred params **Parameters** -- `$0` **any** - - `$0.fishes` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** number of kinds of fish - - `$0.foxes` +- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** + - `options.fishes` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** number of kinds of fish + - `options.foxes` ## withDefault @@ -45,7 +45,7 @@ This method has a type in the description and a default in the code **Parameters** -- `x` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?= 2** +- `x` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** (optional, default `2`) ## Foo @@ -112,7 +112,7 @@ values specified in code. **Parameters** -- `x` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?= 123** an argument +- `x` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** an argument (optional, default `123`) Returns **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** some @@ -132,8 +132,8 @@ iterator destructure (RestElement) **Parameters** -- `$0` **any** - - `$0.x` **any** head of iterator - - `$0.xs` **...any** +- `input` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** + - `input.x` **any** head of iterator + - `input.xs` **...any** Returns **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<any>** rotated such that the last element was the first diff --git a/test/fixture/params.output.md.json b/test/fixture/params.output.md.json index f8f56c216..e0512ec3b 100644 --- a/test/fixture/params.output.md.json +++ b/test/fixture/params.output.md.json @@ -63,6 +63,28 @@ "ordered": false, "type": "list", "children": [ + { + "type": "listItem", + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "inlineCode", + "value": "a" + }, + { + "type": "text", + "value": " " + }, + { + "type": "text", + "value": " " + } + ] + } + ] + }, { "type": "listItem", "children": [ @@ -136,28 +158,6 @@ } ] }, - { - "type": "listItem", - "children": [ - { - "type": "paragraph", - "children": [ - { - "type": "inlineCode", - "value": "a" - }, - { - "type": "text", - "value": " " - }, - { - "type": "text", - "value": " " - } - ] - } - ] - }, { "type": "listItem", "children": [ @@ -198,8 +198,15 @@ "type": "strong", "children": [ { - "type": "text", - "value": "any" + "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object", + "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object", + "type": "link", + "children": [ + { + "type": "text", + "value": "Object" + } + ] } ] }, @@ -351,7 +358,7 @@ "children": [ { "type": "inlineCode", - "value": "$0" + "value": "options" }, { "type": "text", @@ -361,8 +368,15 @@ "type": "strong", "children": [ { - "type": "text", - "value": "any" + "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object", + "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object", + "type": "link", + "children": [ + { + "type": "text", + "value": "Object" + } + ] } ] }, @@ -384,7 +398,7 @@ "children": [ { "type": "inlineCode", - "value": "$0.fishes" + "value": "options.fishes" }, { "type": "text", @@ -457,7 +471,7 @@ "children": [ { "type": "inlineCode", - "value": "$0.foxes" + "value": "options.foxes" }, { "type": "text", @@ -566,16 +580,29 @@ { "type": "text", "value": "?" - }, - { - "type": "text", - "value": "= 2" } ] }, { "type": "text", "value": " " + }, + { + "type": "paragraph", + "children": [ + { + "type": "text", + "value": " (optional, default " + }, + { + "type": "inlineCode", + "value": "2" + }, + { + "type": "text", + "value": ")" + } + ] } ] } @@ -1954,10 +1981,6 @@ { "type": "text", "value": "?" - }, - { - "type": "text", - "value": "= 123" } ] }, @@ -1999,6 +2022,23 @@ }, "indent": [] } + }, + { + "type": "paragraph", + "children": [ + { + "type": "text", + "value": " (optional, default " + }, + { + "type": "inlineCode", + "value": "123" + }, + { + "type": "text", + "value": ")" + } + ] } ] } @@ -2261,7 +2301,7 @@ "children": [ { "type": "inlineCode", - "value": "$0" + "value": "input" }, { "type": "text", @@ -2271,8 +2311,15 @@ "type": "strong", "children": [ { - "type": "text", - "value": "any" + "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array", + "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array", + "type": "link", + "children": [ + { + "type": "text", + "value": "Array" + } + ] } ] }, @@ -2294,7 +2341,7 @@ "children": [ { "type": "inlineCode", - "value": "$0.x" + "value": "input.x" }, { "type": "text", @@ -2360,7 +2407,7 @@ "children": [ { "type": "inlineCode", - "value": "$0.xs" + "value": "input.xs" }, { "type": "text", diff --git a/test/fixture/simple-two.output.json b/test/fixture/simple-two.output.json index a6d86ceea..f8ed76562 100644 --- a/test/fixture/simple-two.output.json +++ b/test/fixture/simple-two.output.json @@ -167,7 +167,8 @@ "type": { "type": "NameExpression", "name": "Number" - } + }, + "properties": [] } ], "properties": [], diff --git a/test/lib/infer/params.js b/test/lib/infer/params.js index 628f3b71a..63188ceb4 100644 --- a/test/lib/infer/params.js +++ b/test/lib/infer/params.js @@ -18,6 +18,101 @@ function evaluate(fn, file) { return inferParams(toComment(fn, file)); } +test('mergeTrees', function(t) { + t.deepEqual( + inferParams.mergeTrees( + [], + [ + { + title: 'param', + description: 'First arg!', + name: 'a', + type: { + type: 'NameExpression', + name: 'string' + } + } + ] + ), + [ + { + title: 'param', + description: 'First arg!', + name: 'a', + type: { + type: 'NameExpression', + name: 'string' + } + } + ] + ); + + t.deepEqual( + inferParams.mergeTrees( + [ + { + title: 'param', + name: '$0', + anonymous: true, + parameterIndex: 0, + type: { + type: 'NameExpression', + name: 'object' + }, + properties: [ + { + title: 'param', + name: '$0.a', + parameterIndex: 0, + type: { + type: 'NameExpression', + name: 'string' + }, + properties: [] + } + ] + } + ], + [ + { + title: 'param', + description: 'First arg!', + name: 'a', + type: { + type: 'NameExpression', + name: 'object' + } + } + ] + ), + [ + { + title: 'param', + description: 'First arg!', + name: 'a', + type: { + type: 'NameExpression', + name: 'object' + }, + properties: [ + { + title: 'param', + name: 'a.a', + parameterIndex: 0, + type: { + type: 'NameExpression', + name: 'string' + }, + properties: [] + } + ] + } + ] + ); + + t.end(); +}); + test('inferParams', function(t) { t.deepEqual( evaluate(function() { @@ -35,6 +130,86 @@ test('inferParams', function(t) { [{ lineNumber: 3, name: 'x', title: 'param' }] ); + t.deepEqual( + evaluate(function() { + /** + * Test + * @param {Object} a renamed destructuring param + */ + var f = function({ x }) {}; + }).params, + [ + { + description: { + children: [ + { + children: [ + { + position: { + end: { + column: 28, + line: 1, + offset: 27 + }, + indent: [], + start: { + column: 1, + line: 1, + offset: 0 + } + }, + type: 'text', + value: 'renamed destructuring param' + } + ], + position: { + end: { + column: 28, + line: 1, + offset: 27 + }, + indent: [], + start: { + column: 1, + line: 1, + offset: 0 + } + }, + type: 'paragraph' + } + ], + position: { + end: { + column: 28, + line: 1, + offset: 27 + }, + start: { + column: 1, + line: 1, + offset: 0 + } + }, + type: 'root' + }, + lineNumber: 2, + name: 'a', + properties: [ + { + lineNumber: 6, + name: 'a.x', + title: 'param' + } + ], + title: 'param', + type: { + name: 'Object', + type: 'NameExpression' + } + } + ] + ); + t.deepEqual(evaluate('/** Test */ var f = (x) => {}').params, [ { lineNumber: 1, name: 'x', title: 'param' } ]); @@ -49,6 +224,78 @@ test('inferParams', function(t) { [{ lineNumber: 5, name: 'x', title: 'param' }] ); + t.deepEqual( + evaluate(function() { + /** Test */ + function f(x = 4) {} + }).params, + [ + { + default: '4', + name: 'x', + title: 'param', + lineNumber: 3, + type: { + expression: null, + type: 'OptionalType' + } + } + ], + 'default params' + ); + + t.deepEqual( + evaluate(function() { + /** Test + * @param {number} x + */ + function f(x = 4) {} + }).params, + [ + { + default: '4', + name: 'x', + title: 'param', + lineNumber: 1, + properties: [], + type: { + expression: { + type: 'NameExpression', + name: 'number' + }, + type: 'OptionalType' + } + } + ], + 'default params with type' + ); + + t.deepEqual( + evaluate(function() { + /** Test */ + function f({ x: y }) {} + }).params, + [ + { + anonymous: true, + name: '$0', + properties: [ + { + lineNumber: 3, + name: '$0.x', + title: 'param' + } + ], + title: 'param', + type: { + name: 'Object', + type: 'NameExpression' + } + } + ], + 'renaming' + ); + t.deepEqual(evaluate('/** Test */ export function f(x) {}').params, [ { lineNumber: 1, name: 'x', title: 'param' } ]); diff --git a/test/lib/nest.js b/test/lib/nest.js index 8210ce45b..fb603cabd 100644 --- a/test/lib/nest.js +++ b/test/lib/nest.js @@ -1,101 +1,117 @@ 'use strict'; -var test = require('tap').test, - parse = require('../../lib/parsers/javascript'), - nest = require('../../lib/nest'); +var test = require('tap').test; +var nestTag = require('../../lib/nest').nestTag; -function toComment(fn, filename) { - return parse( - { - file: filename, - source: fn instanceof Function ? '(' + fn.toString() + ')' : fn - }, - {} - ).map(nest); -} +// Print a tree of tags in a way that's easy to test. +var printTree = indent => + node => + `${new Array(indent + 1).join(' ')}- ${node.name}${node.properties ? '\n' : ''}${(node.properties || [ + ]) + .map(printTree(indent + 1)) + .join('\n')}`; -test('nest params - no params', function(t) { - t.deepEqual( - toComment(function() { - /** @name foo */ - })[0].params, - [], - 'no params' - ); - t.end(); -}); +var printNesting = params => + printTree(0)({ properties: nestTag(params), name: 'root' }); -test('nest params - no nesting', function(t) { - var result = toComment(function() { - /** @param {Object} foo */ - }); - t.equal(result[0].params.length, 1); - t.equal(result[0].params[0].name, 'foo'); - t.equal(result[0].params[0].properties, undefined); +test('nest params - basic', function(t) { + var params = [ + 'foo', + 'foo.bar', + 'foo.bar.third', + 'foo.third', + 'foo.third[].baz' + ].map(name => ({ name })); + t.equal( + printNesting(params), + `- root + - foo + - foo.bar + - foo.bar.third + - foo.third + - foo.third[].baz` + ); t.end(); }); -test('nest params - basic', function(t) { - var result = toComment(function() { - /** - * @param {Object} foo - * @param {string} foo.bar - * @param {string} foo.baz - */ - }); - t.equal(result[0].params.length, 1); - t.equal(result[0].params[0].name, 'foo'); - t.equal(result[0].params[0].properties.length, 2); - t.equal(result[0].params[0].properties[0].name, 'foo.bar'); - t.equal(result[0].params[0].properties[1].name, 'foo.baz'); +test('nest params - multiple roots', function(t) { + var params = ['a', 'b', 'c'].map(name => ({ name })); + t.equal( + printNesting(params), + `- root + - a + - b + - c` + ); t.end(); }); -test('nest properties - basic', function(t) { - var result = toComment(function() { - /** - * @property {Object} foo - * @property {string} foo.bar - * @property {string} foo.baz - */ +test('nest params - missing parent', function(t) { + var params = ['foo', 'foo.bar.third'].map(name => ({ name })); + t.throws(() => { + nestTag(params); }); - t.equal(result[0].properties.length, 1); - t.equal(result[0].properties[0].name, 'foo'); - t.equal(result[0].properties[0].properties.length, 2); - t.equal(result[0].properties[0].properties[0].name, 'foo.bar'); - t.equal(result[0].properties[0].properties[1].name, 'foo.baz'); t.end(); }); -test('nest params - array', function(t) { - var result = toComment(function() { - /** - * @param {Object[]} employees - The employees who are responsible for the project. - * @param {string} employees[].name - The name of an employee. - * @param {string} employees[].department - The employee's department. - */ - }); - t.equal(result[0].params.length, 1); - t.equal(result[0].params[0].name, 'employees'); - t.equal(result[0].params[0].properties.length, 2); - t.equal(result[0].params[0].properties[0].name, 'employees[].name'); - t.equal(result[0].params[0].properties[1].name, 'employees[].department'); +test('nest params - #658', function(t) { + var params = [ + 'state', + 'payload', + 'payload.input_meter_levels', + 'payload.input_meter_levels[].peak', + 'payload.input_meter_levels[].rms', + 'payload.output_meter_levels', + 'payload.output_meter_levels[].peak', + 'payload.output_meter_levels[].rms' + ].map(name => ({ name })); + t.equal( + printNesting(params), + `- root + - state + - payload + - payload.input_meter_levels + - payload.input_meter_levels[].peak + - payload.input_meter_levels[].rms + - payload.output_meter_levels + - payload.output_meter_levels[].peak + - payload.output_meter_levels[].rms` + ); t.end(); }); -test('nest params - missing parent', function(t) { - var result = toComment(function() { - /** @param {string} foo.bar */ - }); - t.equal(result[0].params.length, 1); - t.deepEqual( - result[0].errors[0], - { - message: "@param foo.bar's parent foo not found", - commentLineNumber: 0 - }, - 'correct error message' +test('nest params - #554', function(t) { + var params = [ + 'x', + 'yIn', + 'options', + 'options.sgOption', + 'options.minMaxRatio', + 'options.broadRatio', + 'options.noiseLevel', + 'options.maxCriteria', + 'options.smoothY', + 'options.realTopDetection', + 'options.heightFactor', + 'options.boundaries', + 'options.derivativeThreshold' + ].map(name => ({ name })); + t.equal( + printNesting(params), + `- root + - x + - yIn + - options + - options.sgOption + - options.minMaxRatio + - options.broadRatio + - options.noiseLevel + - options.maxCriteria + - options.smoothY + - options.realTopDetection + - options.heightFactor + - options.boundaries + - options.derivativeThreshold` ); - t.equal(result[0].params[0].name, 'foo.bar'); t.end(); }); diff --git a/test/lib/parse.js b/test/lib/parse.js index 558979c2a..ebc18d566 100644 --- a/test/lib/parse.js +++ b/test/lib/parse.js @@ -115,7 +115,9 @@ test('parse - @description', function(t) { * @description This tagged description wins, and [is markdown](http://markdown.com). */ })[0].description, - remark().parse('This tagged description wins, and [is markdown](http://markdown.com).'), + remark().parse( + 'This tagged description wins, and [is markdown](http://markdown.com).' + ), 'description' ); From e160326248e48fcb4c658970322317f32cfef52c Mon Sep 17 00:00:00 2001 From: Tom Macwright Date: Sun, 16 Apr 2017 21:25:58 -0400 Subject: [PATCH 2/7] Address review comments --- declarations/comment.js | 38 +++++++++++++++++++------------------- lib/infer/params.js | 1 - lib/nest.js | 4 ++-- test/lib/infer/params.js | 31 +++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/declarations/comment.js b/declarations/comment.js index 1e12d0c4c..ecfefe5ce 100644 --- a/declarations/comment.js +++ b/declarations/comment.js @@ -1,4 +1,4 @@ -declare type DocumentationConfig = { +type DocumentationConfig = { polyglot?: boolean, inferPrivate?: boolean, noPackage?: boolean, @@ -12,17 +12,17 @@ declare type DocumentationConfig = { parseExtension: Array }; -declare type InputsConfig = { +type InputsConfig = { inputs: Array, config: DocumentationConfig }; -declare type CommentError = { +type CommentError = { message: string, commentLineNumber?: number }; -declare type DoctrineType = { +type DoctrineType = { elements?: Array, expression?: DoctrineType, applications?: Array, @@ -30,7 +30,7 @@ declare type DoctrineType = { name?: string }; -declare type CommentLoc = { +type CommentLoc = { start: { line: number }, @@ -39,12 +39,12 @@ declare type CommentLoc = { } }; -declare type SourceFile = { +type SourceFile = { source?: string, file: string }; -declare type CommentContext = { +type CommentContext = { sortKey: string, file: string, ast: Object, @@ -53,16 +53,16 @@ declare type CommentContext = { github?: CommentContextGitHub }; -declare type CommentContextGitHub = { +type CommentContextGitHub = { path: string, url: string }; -declare type CommentTagBase = { +type CommentTagBase = { title: string }; -declare type CommentTag = CommentTagBase & { +type CommentTag = CommentTagBase & { name?: string, title: string, description?: Object, @@ -72,7 +72,7 @@ declare type CommentTag = CommentTagBase & { properties?: Array }; -declare type CommentTagNamed = CommentTag & { +type CommentTagNamed = CommentTag & { name?: string, title: string, description?: Object, @@ -82,7 +82,7 @@ declare type CommentTagNamed = CommentTag & { properties?: Array }; -declare type CommentMembers = { +type CommentMembers = { static: Array, instance: Array, events: Array, @@ -90,19 +90,19 @@ declare type CommentMembers = { inner: Array }; -declare type CommentExample = { +type CommentExample = { caption?: string, description?: Object }; -declare type Remark = { +type Remark = { type: string, children: Array }; -declare type Access = 'private' | 'public' | 'protected'; -declare type Scope = 'instance' | 'static' | 'inner' | 'global'; -declare type Kind = +type Access = 'private' | 'public' | 'protected'; +type Scope = 'instance' | 'static' | 'inner' | 'global'; +type Kind = | 'class' | 'constant' | 'event' @@ -116,7 +116,7 @@ declare type Kind = | 'typedef' | 'interface'; -declare type Comment = { +type Comment = { errors: Array, tags: Array, @@ -163,7 +163,7 @@ declare type Comment = { }> }; -declare type ReducedComment = { +type ReducedComment = { name: string, kind: ?Kind, scope?: ?Scope diff --git a/lib/infer/params.js b/lib/infer/params.js index 7de521778..4f6fe9e8f 100644 --- a/lib/infer/params.js +++ b/lib/infer/params.js @@ -9,7 +9,6 @@ const flowDoctrine = require('../flow_doctrine'); const util = require('util'); const debuglog = util.debuglog('infer'); -// TODO: use a constant const PATH_SPLIT_CAPTURING = /(\[])?(\.)/g; function addPrefix(doc /*: CommentTagNamed */, prefix) { diff --git a/lib/nest.js b/lib/nest.js index 4cc0c8559..5dd91d317 100644 --- a/lib/nest.js +++ b/lib/nest.js @@ -5,7 +5,7 @@ var _ = require('lodash'); const PATH_SPLIT = /(?:\[])?\./g; -function rejectUnnamedTags( +function removeUnnamedTags( tags /*: Array */ ) /*: Array */ { return tags.filter(tag => typeof tag.name === 'string'); @@ -42,7 +42,7 @@ var nestTag = ( // Use lodash here both for brevity and also because, unlike JavaScript's // sort, it's stable. ) => - _.sortBy(rejectUnnamedTags(tags), tagDepth).reduce( + _.sortBy(removeUnnamedTags(tags), tagDepth).reduce( (memo, tag) => { function insertTag(node, parts) { // The 'done' case: we're at parts.length === 1, diff --git a/test/lib/infer/params.js b/test/lib/infer/params.js index 63188ceb4..28cd5563d 100644 --- a/test/lib/infer/params.js +++ b/test/lib/infer/params.js @@ -130,6 +130,37 @@ test('inferParams', function(t) { [{ lineNumber: 3, name: 'x', title: 'param' }] ); + t.deepEqual( + evaluate(`/** Test */function f({ x, ...xs }) {};`).params, + [ + { + title: 'param', + name: '$0', + anonymous: true, + type: { + type: 'NameExpression', + name: 'Object' + }, + properties: [ + { + title: 'param', + name: '$0.x', + lineNumber: 1 + }, + { + title: 'param', + name: '$0.xs', + lineNumber: 1, + type: { + type: 'RestType' + } + } + ] + } + ], + 'object spread property' + ); + t.deepEqual( evaluate(function() { /** From 03242f30088db9c82e39a258d3a4e406b46857ea Mon Sep 17 00:00:00 2001 From: Tom Macwright Date: Sun, 16 Apr 2017 21:43:55 -0400 Subject: [PATCH 3/7] Reduce testing node requirement back down to 4 --- circle.yml | 2 +- test/lib/infer/params.js | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/circle.yml b/circle.yml index 0465c21b6..fe4654099 100644 --- a/circle.yml +++ b/circle.yml @@ -1,3 +1,3 @@ machine: node: - version: 7 + version: 4 diff --git a/test/lib/infer/params.js b/test/lib/infer/params.js index 28cd5563d..63540e778 100644 --- a/test/lib/infer/params.js +++ b/test/lib/infer/params.js @@ -162,13 +162,15 @@ test('inferParams', function(t) { ); t.deepEqual( - evaluate(function() { + evaluate( + ` /** * Test * @param {Object} a renamed destructuring param */ var f = function({ x }) {}; - }).params, + ` + ).params, [ { description: { @@ -256,10 +258,12 @@ test('inferParams', function(t) { ); t.deepEqual( - evaluate(function() { + evaluate( + ` /** Test */ function f(x = 4) {} - }).params, + ` + ).params, [ { default: '4', @@ -276,12 +280,14 @@ test('inferParams', function(t) { ); t.deepEqual( - evaluate(function() { + evaluate( + ` /** Test * @param {number} x */ function f(x = 4) {} - }).params, + ` + ).params, [ { default: '4', @@ -302,10 +308,12 @@ test('inferParams', function(t) { ); t.deepEqual( - evaluate(function() { + evaluate( + ` /** Test */ function f({ x: y }) {} - }).params, + ` + ).params, [ { anonymous: true, From 1f99f9c1989c943b31613a9011392713a251b588 Mon Sep 17 00:00:00 2001 From: Tom Macwright Date: Sun, 16 Apr 2017 21:57:51 -0400 Subject: [PATCH 4/7] Don't output empty properties, reduce diff noise --- lib/infer/params.js | 20 +++++++++++++------- test/fixture/_multi-file-input.json | 3 +-- test/fixture/class.output.json | 3 +-- test/fixture/es6-class.output.json | 3 +-- test/fixture/es6.output.json | 9 +++------ test/fixture/inline-link.output.json | 6 ++---- test/fixture/lends.output.json | 6 ++---- test/fixture/literal_types.output.json | 3 +-- test/fixture/memberedclass.output.json | 3 +-- test/fixture/merge-infered-type.output.json | 1 - test/fixture/multisignature.output.json | 3 +-- test/fixture/nest_params.output.json | 3 +-- test/fixture/params.output.json | 17 +++++------------ test/fixture/simple-two.output.json | 3 +-- test/lib/infer/params.js | 1 - 15 files changed, 33 insertions(+), 51 deletions(-) diff --git a/lib/infer/params.js b/lib/infer/params.js index 4f6fe9e8f..63874be98 100644 --- a/lib/infer/params.js +++ b/lib/infer/params.js @@ -297,15 +297,21 @@ function combineTags(inferredTag, explicitTag) { defaultValue = inferredTag.default; } + const hasProperties = (inferredTag.properties && + inferredTag.properties.length) || + (explicitTag.properties && explicitTag.properties.length); + return _.assign( explicitTag, - { - properties: mergeNodes( - inferredTag.properties || [], - explicitTag.properties || [] - ), - type - }, + hasProperties + ? { + properties: mergeNodes( + inferredTag.properties || [], + explicitTag.properties || [] + ) + } + : {}, + { type }, defaultValue ? { default: defaultValue } : {} ); } diff --git a/test/fixture/_multi-file-input.json b/test/fixture/_multi-file-input.json index cf00595cf..11a72d624 100644 --- a/test/fixture/_multi-file-input.json +++ b/test/fixture/_multi-file-input.json @@ -167,8 +167,7 @@ "type": { "type": "NameExpression", "name": "Number" - }, - "properties": [] + } } ], "properties": [], diff --git a/test/fixture/class.output.json b/test/fixture/class.output.json index d909a684e..37f1d9b70 100644 --- a/test/fixture/class.output.json +++ b/test/fixture/class.output.json @@ -329,8 +329,7 @@ "type": { "type": "NameExpression", "name": "boolean" - }, - "properties": [] + } } ], "properties": [], diff --git a/test/fixture/es6-class.output.json b/test/fixture/es6-class.output.json index 45aaee754..78ce308f3 100644 --- a/test/fixture/es6-class.output.json +++ b/test/fixture/es6-class.output.json @@ -295,8 +295,7 @@ "type": { "type": "NameExpression", "name": "string" - }, - "properties": [] + } } ], "properties": [], diff --git a/test/fixture/es6.output.json b/test/fixture/es6.output.json index a63054ec4..596e4a656 100644 --- a/test/fixture/es6.output.json +++ b/test/fixture/es6.output.json @@ -463,8 +463,7 @@ "name": "Number" } ] - }, - "properties": [] + } }, { "title": "param", @@ -1085,8 +1084,7 @@ "type": { "type": "NameExpression", "name": "number" - }, - "properties": [] + } }, { "title": "param", @@ -1147,8 +1145,7 @@ "type": { "type": "NameExpression", "name": "number" - }, - "properties": [] + } } ], "properties": [], diff --git a/test/fixture/inline-link.output.json b/test/fixture/inline-link.output.json index 060654315..95ae461d5 100644 --- a/test/fixture/inline-link.output.json +++ b/test/fixture/inline-link.output.json @@ -158,8 +158,7 @@ "type": { "type": "NameExpression", "name": "number" - }, - "properties": [] + } } ], "properties": [], @@ -582,8 +581,7 @@ "type": { "type": "NameExpression", "name": "number" - }, - "properties": [] + } } ], "properties": [], diff --git a/test/fixture/lends.output.json b/test/fixture/lends.output.json index 3fc2c210f..4a231651f 100644 --- a/test/fixture/lends.output.json +++ b/test/fixture/lends.output.json @@ -272,8 +272,7 @@ "type": { "type": "NameExpression", "name": "string" - }, - "properties": [] + } } ], "properties": [], @@ -524,8 +523,7 @@ "type": { "type": "NameExpression", "name": "string" - }, - "properties": [] + } } ], "properties": [], diff --git a/test/fixture/literal_types.output.json b/test/fixture/literal_types.output.json index 5300b7035..858b92501 100644 --- a/test/fixture/literal_types.output.json +++ b/test/fixture/literal_types.output.json @@ -96,8 +96,7 @@ "value": 3.14 } ] - }, - "properties": [] + } } ], "properties": [], diff --git a/test/fixture/memberedclass.output.json b/test/fixture/memberedclass.output.json index 6d125b531..a817352c9 100644 --- a/test/fixture/memberedclass.output.json +++ b/test/fixture/memberedclass.output.json @@ -268,8 +268,7 @@ "type": { "type": "NameExpression", "name": "boolean" - }, - "properties": [] + } } ], "properties": [], diff --git a/test/fixture/merge-infered-type.output.json b/test/fixture/merge-infered-type.output.json index b424e90b9..61f6b15c2 100644 --- a/test/fixture/merge-infered-type.output.json +++ b/test/fixture/merge-infered-type.output.json @@ -183,7 +183,6 @@ } } }, - "properties": [], "type": { "type": "NameExpression", "name": "number" diff --git a/test/fixture/multisignature.output.json b/test/fixture/multisignature.output.json index 4a22e59c0..ba7426e9a 100644 --- a/test/fixture/multisignature.output.json +++ b/test/fixture/multisignature.output.json @@ -335,8 +335,7 @@ "type": { "type": "NameExpression", "name": "Date" - }, - "properties": [] + } } ], "properties": [], diff --git a/test/fixture/nest_params.output.json b/test/fixture/nest_params.output.json index a444a5767..70a9cf890 100644 --- a/test/fixture/nest_params.output.json +++ b/test/fixture/nest_params.output.json @@ -339,8 +339,7 @@ "name": "string" } }, - "default": "minion", - "properties": [] + "default": "minion" } ], "properties": [], diff --git a/test/fixture/params.output.json b/test/fixture/params.output.json index 997f3c05e..2f16910d8 100644 --- a/test/fixture/params.output.json +++ b/test/fixture/params.output.json @@ -154,8 +154,7 @@ "type": { "type": "NameExpression", "name": "number" - }, - "properties": [] + } }, { "title": "param", @@ -380,8 +379,7 @@ "type": { "type": "NameExpression", "name": "String" - }, - "properties": [] + } }, { "title": "param", @@ -515,7 +513,6 @@ "name": "number" } }, - "properties": [], "default": "2" } ], @@ -782,8 +779,7 @@ "type": { "type": "NameExpression", "name": "number" - }, - "properties": [] + } } ], "properties": [], @@ -2223,7 +2219,6 @@ "name": "number" } }, - "properties": [], "default": "123" } ], @@ -2456,8 +2451,7 @@ "offset": 22 } } - }, - "properties": [] + } } ], "properties": [], @@ -2699,8 +2693,7 @@ "type": { "type": "NameExpression", "name": "any" - }, - "properties": [] + } }, { "title": "param", diff --git a/test/fixture/simple-two.output.json b/test/fixture/simple-two.output.json index f8ed76562..a6d86ceea 100644 --- a/test/fixture/simple-two.output.json +++ b/test/fixture/simple-two.output.json @@ -167,8 +167,7 @@ "type": { "type": "NameExpression", "name": "Number" - }, - "properties": [] + } } ], "properties": [], diff --git a/test/lib/infer/params.js b/test/lib/infer/params.js index 63540e778..a2f05646c 100644 --- a/test/lib/infer/params.js +++ b/test/lib/infer/params.js @@ -294,7 +294,6 @@ test('inferParams', function(t) { name: 'x', title: 'param', lineNumber: 1, - properties: [], type: { expression: { type: 'NameExpression', From e0fa855b19f37dc530452bcbec12e24d42c635ec Mon Sep 17 00:00:00 2001 From: Tom Macwright Date: Sun, 16 Apr 2017 22:13:05 -0400 Subject: [PATCH 5/7] Rearrange and document params --- lib/infer/params.js | 86 ++++++++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/lib/infer/params.js b/lib/infer/params.js index 63874be98..ed18f93a8 100644 --- a/lib/infer/params.js +++ b/lib/infer/params.js @@ -9,14 +9,57 @@ const flowDoctrine = require('../flow_doctrine'); const util = require('util'); const debuglog = util.debuglog('infer'); -const PATH_SPLIT_CAPTURING = /(\[])?(\.)/g; +/** + * Infers param tags by reading function parameter names + * + * @param {Object} comment parsed comment + * @returns {Object} comment with parameters + */ +function inferParams(comment /*: Comment */) { + var path = findTarget(comment.context.ast); + + // In case of `/** */ var x = function () {}` findTarget returns + // the declarator. + if (t.isVariableDeclarator(path)) { + path = path.get('init'); + } + + if (!t.isFunction(path)) { + return comment; + } + // 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 + ) + }); +} + +// Utility methods ============================================================ +// function addPrefix(doc /*: CommentTagNamed */, prefix) { return _.assign(doc, { name: prefix + doc.name }); } +const PATH_SPLIT_CAPTURING = /(\[])?(\.)/g; +/** + * Index tags by their `name` property into an ES6 map. + */ +function mapTags(tags) { + return new Map( + tags.map(tag => { + return [tag.name, tag]; + }) + ); +} + +// ___toDoc methods ============================================================ +// +// These methods take Babel AST nodes and output equivalent JSDoc parameter tags. function destructuringObjectParamToDoc(param, i, prefix) /*: CommentTag */ { return { title: 'param', @@ -174,38 +217,19 @@ function paramToDoc( } } -/** - * Infers param tags by reading function parameter names - * - * @param {Object} comment parsed comment - * @returns {Object} comment with parameters - */ -function inferParams(comment /*: Comment */) { - var path = findTarget(comment.context.ast); - - // In case of `/** */ var x = function () {}` findTarget returns - // the declarator. - if (t.isVariableDeclarator(path)) { - path = path.get('init'); - } - - if (!t.isFunction(path)) { - return comment; - } - - // 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 - ) - }); -} - /** * Recurse through a potentially nested parameter tag, * replacing the auto-generated name, like $0, with an explicit - * name provided from a JSDoc comment + * name provided from a JSDoc comment. For instance, if you have a code + * block like + * + * function f({ x }); + * + * It would by default be documented with a first param $0, with a member $0.x + * + * If you specify the name of the param, then it could be documented with, say, + * options and options.x. So we need to recursively rename not just $0 but + * also $0.x and maybe $0.x.y.z all to options.x and options.x.y.z */ function renameTree(node, explicitName) { var parts = node.name.split(PATH_SPLIT_CAPTURING); @@ -216,8 +240,6 @@ function renameTree(node, explicitName) { } } -var mapTags = tags => new Map(tags.map(tag => [tag.name, tag])); - function mergeTrees(inferred, explicit) { // The first order of business is ensuring that the root types are specified // in the right order. For the order of arguments, the inferred reality From af0daf818206da68e3182e701899ff4cf0e4736e Mon Sep 17 00:00:00 2001 From: Tom Macwright Date: Tue, 18 Apr 2017 20:18:59 -0400 Subject: [PATCH 6/7] 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 --- lib/infer/params.js | 248 ++++++++++++++--------------- test/fixture/es6.output-toc.md | 8 +- test/fixture/es6.output.json | 8 +- test/fixture/es6.output.md | 8 +- test/fixture/es6.output.md.json | 8 +- test/fixture/params.output.json | 5 + test/fixture/params.output.md | 1 + test/fixture/params.output.md.json | 22 +++ test/lib/infer/params.js | 28 ++++ 9 files changed, 189 insertions(+), 147 deletions(-) diff --git a/lib/infer/params.js b/lib/infer/params.js index ed18f93a8..2861bee70 100644 --- a/lib/infer/params.js +++ b/lib/infer/params.js @@ -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; /** @@ -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 @@ -184,27 +73,124 @@ function restParamToDoc(param) /*: CommentTag */ { */ function paramToDoc( param, - i /*: number */, - prefix /*: string */ -) /*: CommentTag */ { - // ES6 default + prefix /*: string */, + i /*: ?number */ +) /*: CommentTag|Array */ { + 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 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 + 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 }; @@ -213,7 +199,7 @@ function paramToDoc( newParam.type = flowDoctrine(param.typeAnnotation.typeAnnotation); } - return addPrefix(newParam, prefix); + return newParam; } } diff --git a/test/fixture/es6.output-toc.md b/test/fixture/es6.output-toc.md index 7e731557a..4060592c0 100644 --- a/test/fixture/es6.output-toc.md +++ b/test/fixture/es6.output-toc.md @@ -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** @@ -135,6 +135,6 @@ Regression check for #498 - `array1` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<T>** - `array2` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<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)** diff --git a/test/fixture/es6.output.json b/test/fixture/es6.output.json index 596e4a656..2f66ac9b6 100644 --- a/test/fixture/es6.output.json +++ b/test/fixture/es6.output.json @@ -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 } ] @@ -2809,7 +2809,7 @@ } } }, - "default": "(a: T, b: T): boolean => a === b" + "default": "(a:T,b:T):boolean=>a===b" } ], "properties": [], diff --git a/test/fixture/es6.output.md b/test/fixture/es6.output.md index 84c9e963e..416e00c6a 100644 --- a/test/fixture/es6.output.md +++ b/test/fixture/es6.output.md @@ -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** @@ -158,6 +158,6 @@ Regression check for #498 - `array1` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<T>** - `array2` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<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)** diff --git a/test/fixture/es6.output.md.json b/test/fixture/es6.output.md.json index 74617b58a..3c6e7eb2b 100644 --- a/test/fixture/es6.output.md.json +++ b/test/fixture/es6.output.md.json @@ -379,7 +379,7 @@ "children": [ { "type": "inlineCode", - "value": "$0.a" + "value": "$0.0" }, { "type": "text", @@ -401,7 +401,7 @@ "children": [ { "type": "inlineCode", - "value": "$0.b" + "value": "$0.1" }, { "type": "text", @@ -423,7 +423,7 @@ "children": [ { "type": "inlineCode", - "value": "$0.c" + "value": "$0.2" }, { "type": "text", @@ -2229,7 +2229,7 @@ }, { "type": "inlineCode", - "value": "(a: T, b: T): boolean => a === b" + "value": "(a:T,b:T):boolean=>a===b" }, { "type": "text", diff --git a/test/fixture/params.output.json b/test/fixture/params.output.json index 2f16910d8..095ba443a 100644 --- a/test/fixture/params.output.json +++ b/test/fixture/params.output.json @@ -2695,6 +2695,11 @@ "name": "any" } }, + { + "title": "param", + "name": "input.0", + "lineNumber": 109 + }, { "title": "param", "name": "input.xs", diff --git a/test/fixture/params.output.md b/test/fixture/params.output.md index 66737b81b..13a12b411 100644 --- a/test/fixture/params.output.md +++ b/test/fixture/params.output.md @@ -134,6 +134,7 @@ iterator destructure (RestElement) - `input` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** - `input.x` **any** head of iterator + - `input.0` - `input.xs` **...any** Returns **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<any>** rotated such that the last element was the first diff --git a/test/fixture/params.output.md.json b/test/fixture/params.output.md.json index e0512ec3b..07ed8d7f5 100644 --- a/test/fixture/params.output.md.json +++ b/test/fixture/params.output.md.json @@ -2399,6 +2399,28 @@ } ] }, + { + "type": "listItem", + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "inlineCode", + "value": "input.0" + }, + { + "type": "text", + "value": " " + }, + { + "type": "text", + "value": " " + } + ] + } + ] + }, { "type": "listItem", "children": [ diff --git a/test/lib/infer/params.js b/test/lib/infer/params.js index a2f05646c..8049ee6de 100644 --- a/test/lib/infer/params.js +++ b/test/lib/infer/params.js @@ -334,6 +334,34 @@ test('inferParams', function(t) { 'renaming' ); + t.deepEqual( + evaluate( + ` + /** Test */ + function f({ x: { y: { z } } }) {} + ` + ).params, + [ + { + anonymous: true, + name: '$0', + properties: [ + { + lineNumber: 3, + name: '$0.x.y.z', + title: 'param' + } + ], + title: 'param', + type: { + name: 'Object', + type: 'NameExpression' + } + } + ], + 'renaming' + ); + t.deepEqual(evaluate('/** Test */ export function f(x) {}').params, [ { lineNumber: 1, name: 'x', title: 'param' } ]); From d2ef6a7258b21346565306f383b90e1109c61644 Mon Sep 17 00:00:00 2001 From: Tom Macwright Date: Fri, 21 Apr 2017 17:23:27 -0400 Subject: [PATCH 7/7] Use temporary fork to get through blocker --- lib/output/util/format_type.js | 3 +- lib/output/util/formatters.js | 2 +- lib/parse.js | 2 +- package.json | 2 +- test/fixture/params.input.js | 4 +- test/fixture/params.output.json | 94 +++++++++++++++++++++--------- test/fixture/params.output.md | 5 +- test/fixture/params.output.md.json | 59 +++++++++++-------- test/format_type.js | 2 +- 9 files changed, 112 insertions(+), 61 deletions(-) diff --git a/lib/output/util/format_type.js b/lib/output/util/format_type.js index 072542866..37d79b8b4 100644 --- a/lib/output/util/format_type.js +++ b/lib/output/util/format_type.js @@ -1,6 +1,7 @@ /* @flow */ 'use strict'; -var Syntax = require('doctrine').Syntax, u = require('unist-builder'); +var Syntax = require('doctrine-temporary-fork').Syntax, + u = require('unist-builder'); /** * Shortcut to create a new text node diff --git a/lib/output/util/formatters.js b/lib/output/util/formatters.js index c368c3eb2..861df2114 100644 --- a/lib/output/util/formatters.js +++ b/lib/output/util/formatters.js @@ -2,7 +2,7 @@ 'use strict'; var remark = require('remark'), html = require('remark-html'), - Syntax = require('doctrine').Syntax, + Syntax = require('doctrine-temporary-fork').Syntax, u = require('unist-builder'), _rerouteLinks = require('./reroute_links'), highlighter = require('../highlighter'), diff --git a/lib/parse.js b/lib/parse.js index eccd60573..653a0a9a8 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -1,7 +1,7 @@ 'use strict'; /* @flow */ -var doctrine = require('doctrine'); +var doctrine = require('doctrine-temporary-fork'); var parseMarkdown = require('./parse_markdown'); /** diff --git a/package.json b/package.json index ffbd555b4..94330a55d 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "chokidar": "^1.2.0", "concat-stream": "^1.5.0", "disparity": "^2.0.0", - "doctrine": "^2.0.0", + "doctrine-temporary-fork": "2.0.0-alpha-allowarrayindex", "get-comments": "^1.0.1", "git-url-parse": "^6.0.1", "github-slugger": "1.1.1", diff --git a/test/fixture/params.input.js b/test/fixture/params.input.js index c9522355c..50e7b514e 100644 --- a/test/fixture/params.input.js +++ b/test/fixture/params.input.js @@ -101,8 +101,8 @@ function foo(address) { * iterator destructure (RestElement) * * @param {Array} input - * @param {any} input.x head of iterator - * @param {any[]} ...input.xs body of iterator + * @param {any} input.0 head of iterator + * @param {...any} input.xs body of iterator * * @returns {any[]} rotated such that the last element was the first */ diff --git a/test/fixture/params.output.json b/test/fixture/params.output.json index 095ba443a..129cc02b3 100644 --- a/test/fixture/params.output.json +++ b/test/fixture/params.output.json @@ -2552,29 +2552,20 @@ "type": "NameExpression", "name": "any" }, - "name": "input.x" + "name": "input.0" }, { "title": "param", - "description": "...input.xs body of iterator", + "description": "body of iterator", "lineNumber": 6, "type": { - "type": "TypeApplication", + "type": "RestType", "expression": { "type": "NameExpression", - "name": "Array" - }, - "applications": [ - { - "type": "NameExpression", - "name": "any" - } - ] + "name": "any" + } }, - "name": null, - "errors": [ - "Missing or invalid tag name" - ] + "name": "input.xs" }, { "title": "returns", @@ -2618,11 +2609,7 @@ } }, "augments": [], - "errors": [ - { - "message": "Missing or invalid tag name" - } - ], + "errors": [], "examples": [], "params": [ { @@ -2636,7 +2623,7 @@ "properties": [ { "title": "param", - "name": "input.x", + "name": "input.0", "lineNumber": 5, "description": { "type": "root", @@ -2695,17 +2682,68 @@ "name": "any" } }, - { - "title": "param", - "name": "input.0", - "lineNumber": 109 - }, { "title": "param", "name": "input.xs", - "lineNumber": 109, + "lineNumber": 6, + "description": { + "type": "root", + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "text", + "value": "body of iterator", + "position": { + "start": { + "line": 1, + "column": 1, + "offset": 0 + }, + "end": { + "line": 1, + "column": 17, + "offset": 16 + }, + "indent": [] + } + } + ], + "position": { + "start": { + "line": 1, + "column": 1, + "offset": 0 + }, + "end": { + "line": 1, + "column": 17, + "offset": 16 + }, + "indent": [] + } + } + ], + "position": { + "start": { + "line": 1, + "column": 1, + "offset": 0 + }, + "end": { + "line": 1, + "column": 17, + "offset": 16 + } + } + }, "type": { - "type": "RestType" + "type": "RestType", + "expression": { + "type": "NameExpression", + "name": "any" + } } } ] diff --git a/test/fixture/params.output.md b/test/fixture/params.output.md index 13a12b411..6413e14bf 100644 --- a/test/fixture/params.output.md +++ b/test/fixture/params.output.md @@ -133,8 +133,7 @@ iterator destructure (RestElement) **Parameters** - `input` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** - - `input.x` **any** head of iterator - - `input.0` - - `input.xs` **...any** + - `input.0` **any** head of iterator + - `input.xs` **...any** body of iterator Returns **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<any>** rotated such that the last element was the first diff --git a/test/fixture/params.output.md.json b/test/fixture/params.output.md.json index 07ed8d7f5..69f263493 100644 --- a/test/fixture/params.output.md.json +++ b/test/fixture/params.output.md.json @@ -2341,7 +2341,7 @@ "children": [ { "type": "inlineCode", - "value": "input.x" + "value": "input.0" }, { "type": "text", @@ -2399,28 +2399,6 @@ } ] }, - { - "type": "listItem", - "children": [ - { - "type": "paragraph", - "children": [ - { - "type": "inlineCode", - "value": "input.0" - }, - { - "type": "text", - "value": " " - }, - { - "type": "text", - "value": " " - } - ] - } - ] - }, { "type": "listItem", "children": [ @@ -2451,6 +2429,41 @@ { "type": "text", "value": " " + }, + { + "type": "paragraph", + "children": [ + { + "type": "text", + "value": "body of iterator", + "position": { + "start": { + "line": 1, + "column": 1, + "offset": 0 + }, + "end": { + "line": 1, + "column": 17, + "offset": 16 + }, + "indent": [] + } + } + ], + "position": { + "start": { + "line": 1, + "column": 1, + "offset": 0 + }, + "end": { + "line": 1, + "column": 17, + "offset": 16 + }, + "indent": [] + } } ] } diff --git a/test/format_type.js b/test/format_type.js index 827a3dcca..667c7613d 100644 --- a/test/format_type.js +++ b/test/format_type.js @@ -4,7 +4,7 @@ var _formatType = require('../lib/output/util/format_type'), LinkerStack = require('../lib/output/util/linker_stack'), remark = require('remark'), - parse = require('doctrine').parse, + parse = require('doctrine-temporary-fork').parse, test = require('tap').test; function stringify(children) {