function rewriteObjectDefinePropertyOnExports()

in src/googmodule.ts [789:861]


      function rewriteObjectDefinePropertyOnExports(
          stmt: ts.ExpressionStatement): ts.Statement|null {
        // Verify this node is a function call.
        if (!ts.isCallExpression(stmt.expression)) return null;

        // Verify the node being called looks like `a.b`.
        const callExpr = stmt.expression;
        if (!ts.isPropertyAccessExpression(callExpr.expression)) return null;

        // Verify that the `a.b`-ish thing is actully `Object.defineProperty`.
        const propAccess = callExpr.expression;
        if (!ts.isIdentifier(propAccess.expression)) return null;
        if (propAccess.expression.text !== 'Object') return null;
        if (propAccess.name.text !== 'defineProperty') return null;

        // Grab each argument to `Object.defineProperty`, and verify that there
        // are exactly three arguments. The first argument should be the global
        // `exports` object, the second is the exported name as a string
        // literal, and the third is a configuration object.
        if (callExpr.arguments.length !== 3) return null;
        const [objDefArg1, objDefArg2, objDefArg3] = callExpr.arguments;
        if (!ts.isIdentifier(objDefArg1)) return null;
        if (objDefArg1.text !== 'exports') return null;
        if (!ts.isStringLiteral(objDefArg2)) return null;
        if (!ts.isObjectLiteralExpression(objDefArg3)) return null;

        // Returns a "finder" function to location an object property.
        function findPropNamed(name: string) {
          return (p: ts.ObjectLiteralElementLike) => {
            return ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) &&
                p.name.text === name;
          };
        }

        // Verify that the export is marked as enumerable. If it isn't then this
        // was not generated by TypeScript.
        const enumerableConfig =
            objDefArg3.properties.find(findPropNamed('enumerable'));
        if (!enumerableConfig) return null;
        if (!ts.isPropertyAssignment(enumerableConfig)) return null;
        if (enumerableConfig.initializer.kind !== ts.SyntaxKind.TrueKeyword) {
          return null;
        }

        // Verify that the export has a getter function.
        const getConfig = objDefArg3.properties.find(findPropNamed('get'));
        if (!getConfig) return null;
        if (!ts.isPropertyAssignment(getConfig)) return null;
        if (!ts.isFunctionExpression(getConfig.initializer)) return null;

        // Verify that the getter function has exactly one statement that is a
        // return statement. The node being returned is the real exported value.
        const getterFunc = getConfig.initializer;
        if (getterFunc.body.statements.length !== 1) return null;
        const getterReturn = getterFunc.body.statements[0];
        if (!ts.isReturnStatement(getterReturn)) return null;
        const realExportValue = getterReturn.expression;
        if (!realExportValue) return null;

        // Create a new export statement using the exported name found as the
        // second argument to `Object.defineProperty` with the value of the
        // node returned by the getter function.
        const exportStmt = ts.setOriginalNode(
            ts.setTextRange(
                ts.createExpressionStatement(ts.createAssignment(
                    ts.createPropertyAccess(
                        ts.createIdentifier('exports'), objDefArg2.text),
                    realExportValue)),
                stmt),
            stmt);

        return exportStmt;
      }