docs: function parse( doxComment, options ) {
     if( !( 'ctx' in doxComment ) ) {
        doxComment.ctx = false;
     }
  
     const parsed = {
        // An explicitly given name is used in favor of a derived one.
        name: ( tagsByType( doxComment.tags, 'name', 'directive', 'injection', 'module' )[ 0 ] || {} ).string ||
           doxComment.ctx.name ||
           '- unknown -',
        description: description( doxComment ),
        dox: doxComment
     };
  
     const optional = [];
     parsed.params = tagsByType( doxComment.tags, 'param' )
        .map( tag => {
           const cleanName = tag.name.replace( /^\[?([^\]]*)]?$/g, '$1' );
           const parents = cleanName.split( '.' ).slice( 0, -1 );
           if( tag.optional ) {
              optional.push( cleanName );
           }
           else if( parents.some( p => optional.indexOf( p ) !== -1 ) ) {
              // a property of an optional object parameter is optional too
              optional.push( cleanName );
              tag.optional = true;
           }
  
           return {
              name: cleanName,
              types: tag.types.length === 0 ? [ '*' ] : tag.types,
              description: convertLineBreaks( description( tag ) ),
              dox: tag
           };
        } );
  
     parsed.paramsForArgsList = parsed.params
        // filter out object parameter properties for argument list
        .filter( param => param.name.indexOf( '.' ) === -1 )
        .map( param => param.name );
  
     parsed.returns = tagsByType( doxComment.tags, 'return', 'returns' )
        .map( tag =>
           ({
              name: tag.name,
              types: tag.types.length === 0 ? [ '*' ] : tag.types,
              description: convertLineBreaks( description( tag ) ),
              dox: tag
           })
        )[ 0 ] || null;
  
     if( options.verbose ) {
        /* eslint-disable no-console */
        console.log( JSON.stringify( parsed, null, 3 ) );
        /* eslint-enable no-console */
     }
  
     return parsed;
  }