docs: function getCommentedFunctionNode(node) {
      if (!node.leadingComments) {
          // JSDoc comments are always before the function, so if there is
          // nothing here, we ain't interested.
          return null;
      }
      // console.log("=================");
      // console.log("type: " + node.type);
      // console.log(util.inspect(node));
      /*
       * We handle the following function representations:
       *
       *     Type               Path to Function              Example
       * ==========================================================================================
       * FunctionDeclaration           -                  function foo(bar) {}
       * VariableDeclaration   .declarations[0].init      var foo = function(bar) {}
       * ExpressionStatement   .expression.right          ObjClass.prototype.foo = function(bar) {}
       * MethodDefinition      .value                     class ObjClass { foo(bar) {} }
       * Property              .value                     var obj = { key: function(bar) {} }
       * ReturnStatement       .argument                  return function(foo, bar) {}
       * ArrowFunctionExpression       -                  (foo, bar) => {}
       * ExportNamedDeclaration .declaration              export function foo(bar) {}
       *
       */
      var nodeTypes = [
          "FunctionDeclaration", "ExpressionStatement", "VariableDeclaration",
          "MethodDefinition", "Property", "ReturnStatement", "ArrowFunctionExpression",
          "ExportNamedDeclaration"
      ];
      if (nodeTypes.indexOf(node.type) === -1) {
          return null;
      }
      var funcNode = null;
      switch (node.type) {
          case "FunctionDeclaration":
          case "ArrowFunctionExpression":
              funcNode = node;
              break;
          case "VariableDeclaration":
              funcNode = node.declarations[0].init;
              break;
          case "ExpressionStatement":
              funcNode = node.expression.right;
              break;
          case "MethodDefinition":
              funcNode = node.value;
              break;
          case "Property":
              funcNode = node.value;
              break;
          case "ReturnStatement":
              funcNode = node.argument;
              break;
          case "ExportNamedDeclaration":
              var declaration = node.declaration;
              if (declaration.type === 'VariableDeclaration') {
                  funcNode = declaration.declarations[0].init;
              } else {
                  funcNode = declaration
              }
              break;
      }
      var funcNodeTypes = ["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"];
      if (!funcNode || funcNodeTypes.indexOf(funcNode.type) === -1) {
          // We can't find a function here which can map to leadingComments.
          return null;
      }
      var funcDocs = null;
      for (var i=0; i<node.leadingComments.length; i++) {
          // Block comments are either JSDoc or flow-jsdoc specific in-inline syntax
          if (node.leadingComments[i].type === "Block") {
              funcDocs = extractJsdoc(node.leadingComments[i].value);
              if (funcDocs) { break; }
              // may be inline form with /* */
              funcDocs = extractInlineAnnotations(funcNode, node.leadingComments[i].value);
              if (funcDocs) {
                  node.leadingComments[i].update("");
                  break;
              }
          }
          else if (node.leadingComments[i].type === "Line") {
              // Line comments can only be flow-jsdoc specific in-line syntax.
              funcDocs = extractInlineAnnotations(funcNode, node.leadingComments[i].value);
              if (funcDocs) {
                  node.leadingComments[i].update("");
                  break;
              }
          }
      }
  
      return {
          node: funcNode,
          jsdoc: funcDocs
      };
  }