build/generateExterns.js
function createExternsFromConstructor(className, constructorNode) {
  // Example code:
  //
  // /** @interface @exportInterface */
  // FooLike = function() {};
  //
  // /** @exportInterface @type {number} */
  // FooLike.prototype.bar;
  //
  // /** @constructor @export @implements {FooLike} */
  // Foo = function() {
  //   /** @override @exportInterface */
  //   this.bar = 10;
  // };
  //
  // Example externs:
  //
  // /**
  //  * Generated by createExternFromExportNode:
  //  * @constructor @implements {FooLike}
  //  */
  // Foo = function() {}
  //
  // /**
  //  * Generated by createExternsFromConstructor:
  //  * @override
  //  */
  // Foo.prototype.bar;

  var expressionStatements = getAllExpressionStatements(constructorNode);
  var externString = '';

  expressionStatements.forEach(function(statement) {
    var left = statement.expression.left;
    var right = statement.expression.right;

    // Skip anything that isn't an assignment to a member of "this".
    if (statement.expression.type != 'AssignmentExpression' ||
        left.type != 'MemberExpression' ||
        left.object.type != 'ThisExpression')
      return;

    console.assert(left);
    console.assert(right);

    // Skip anything that isn't exported.
    var comment = getLeadingBlockComment(statement);
    if (!EXPORT_REGEX.test(comment))
      return;

    comment = removeExportAnnotationsFromComment(comment);

    console.assert(left.property.type == 'Identifier');
    var name = className + '.prototype.' + left.property.name;
    externString += comment + '\n' + name + ';\n';
  });

  return externString;
}
function createExternsFromConstructor(className, constructorNode) {
  // Example code:
  //
  // /** @interface @exportInterface */
  // FooLike = function() {};
  //
  // /** @exportInterface @type {number} */
  // FooLike.prototype.bar;
  //
  // /** @constructor @export @implements {FooLike} */
  // Foo = function() {
  //   /** @override @exportInterface */
  //   this.bar = 10;
  // };
  //
  // Example externs:
  //
  // /**
  //  * Generated by createExternFromExportNode:
  //  * @constructor @implements {FooLike}
  //  */
  // Foo = function() {}
  //
  // /**
  //  * Generated by createExternsFromConstructor:
  //  * @override
  //  */
  // Foo.prototype.bar;

  var expressionStatements = getAllExpressionStatements(constructorNode);
  var externString = '';

  expressionStatements.forEach(function(statement) {
    var left = statement.expression.left;
    var right = statement.expression.right;

    // Skip anything that isn't an assignment to a member of "this".
    if (statement.expression.type != 'AssignmentExpression' ||
        left.type != 'MemberExpression' ||
        left.object.type != 'ThisExpression')
      return;

    console.assert(left);
    console.assert(right);

    // Skip anything that isn't exported.
    var comment = getLeadingBlockComment(statement);
    if (!EXPORT_REGEX.test(comment))
      return;

    comment = removeExportAnnotationsFromComment(comment);

    console.assert(left.property.type == 'Identifier');
    var name = className + '.prototype.' + left.property.name;
    externString += comment + '\n' + name + ';\n';
  });

  return externString;
}
function createExternsFromConstructor ( className , constructorNode ) { // Example code: // // /** @interface @exportInterface */ // FooLike = function() {}; // // /** @exportInterface @type {number} */ // FooLike.prototype.bar; // // /** @constructor @export @implements {FooLike} */ // Foo = function() { //   /** @override @exportInterface */ //   this.bar = 10; // }; // // Example externs: // // /** //  * Generated by createExternFromExportNode: //  * @constructor @implements {FooLike} //  */ // Foo = function() {} // // /** //  * Generated by createExternsFromConstructor: //  * @override //  */ // Foo.prototype.bar; var expressionStatements = getAllExpressionStatements ( constructorNode ) ; var externString = '' ; expressionStatements . forEach ( function ( statement ) { var left = statement . expression . left ; var right = statement . expression . right ; // Skip anything that isn't an assignment to a member of "this". if ( statement . expression . type != 'AssignmentExpression' || left . type != 'MemberExpression' || left . object . type != 'ThisExpression' ) return ; console . assert ( left ) ; console . assert ( right ) ; // Skip anything that isn't exported. var comment = getLeadingBlockComment ( statement ) ; if ( ! EXPORT_REGEX . test ( comment ) ) return ; comment = removeExportAnnotationsFromComment ( comment ) ; console . assert ( left . property . type == 'Identifier' ) ; var name = className + '.prototype.' + left . property . name ; externString += comment + '\n' + name + ';\n' ; } ) ; return externString ; }
Look for exports in a constructor body.  If we don't do this, we may end up
with errors about classes not fully implementing their interfaces.  In
reality, the interface is implemented by assigning members on "this".

@param {string} className
@param {ASTNode} constructorNode
@return {string}
Look for exports in a constructor body . If we don t do this we may end up with errors about classes not fully implementing their interfaces . In reality the interface is implemented by assigning members on this .