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;
}