in src/googmodule.ts [880:1026]
function visitTopLevelStatement(
statements: ts.Statement[], sf: ts.SourceFile,
node: ts.Statement): void {
// Handle each particular case by adding node to statements, then
// return. For unhandled cases, break to jump to the default handling
// below.
// In JS transpilation mode, always rewrite `require('tslib')` to
// goog.require('tslib'), ignoring normal module resolution.
if (host.isJsTranspilation) {
const rewrittenTsLib = maybeRewriteRequireTslib(node);
if (rewrittenTsLib) {
statements.push(rewrittenTsLib);
return;
}
}
switch (node.kind) {
case ts.SyntaxKind.ExpressionStatement: {
const exprStmt = node as ts.ExpressionStatement;
// Check for "use strict" and certain Object.defineProperty and skip
// it if necessary.
if (isUseStrict(exprStmt) || isEsModuleProperty(exprStmt)) {
stmts.push(createNotEmittedStatementWithComments(sf, exprStmt));
return;
}
// If we have not already seen the defaulted export assignment
// initializing all exports to `void 0`, skip the statement and mark
// that we have have now seen it.
if (checkExportsVoid0Assignment(exprStmt.expression)) {
stmts.push(createNotEmittedStatementWithComments(sf, exprStmt));
return;
}
// Check for:
// module.exports = ...;
const modExports = rewriteModuleExportsAssignment(exprStmt);
if (modExports) {
stmts.push(modExports);
return;
}
// Check for use of the comma operator.
// This occurs in code like
// exports.a = ..., exports.b = ...;
// which we want to change into multiple statements.
const commaExpanded = rewriteCommaExpressions(exprStmt.expression);
if (commaExpanded) {
stmts.push(...commaExpanded);
return;
}
// Check for:
// exports.ns = require('...');
// which is generated by the `export * as ns from` syntax.
const exportStarAsNs = maybeRewriteExportStarAsNs(exprStmt);
if (exportStarAsNs) {
stmts.push(...exportStarAsNs);
return;
}
// Checks for:
// Object.defineProperty(exports, 'a', {
// enumerable: true, get: { return ...; }
// })
// which is a live binding generated when re-exporting from another
// module.
const exportFromObjDefProp =
rewriteObjectDefinePropertyOnExports(exprStmt);
if (exportFromObjDefProp) {
stmts.push(exportFromObjDefProp);
return;
}
// The rest of this block handles only some function call forms:
// goog.declareModuleId(...);
// require('foo');
// __exportStar(require('foo'), ...);
const expr = exprStmt.expression;
if (!ts.isCallExpression(expr)) break;
let callExpr = expr;
// Check for declareModuleId.
const declaredModuleId =
maybeRewriteDeclareModuleId(exprStmt, callExpr);
if (declaredModuleId) {
statements.push(declaredModuleId);
return;
}
// Check for __exportStar, the commonjs version of 'export *'.
// export * creates either a pure top-level '__export(require(...))'
// or the imported version, 'tslib.__exportStar(require(...))'. The
// imported version is only substituted later on though, so appears
// as a plain "__exportStar" on the top level here.
const isExportStar = ts.isIdentifier(expr.expression) &&
(expr.expression.text === '__exportStar' ||
expr.expression.text === '__export');
let newIdent: ts.Identifier|undefined;
if (isExportStar) {
// Extract the goog.require() from the call. (It will be verified
// as a goog.require() below.)
callExpr = expr.arguments[0] as ts.CallExpression;
newIdent = ts.createIdentifier(nextModuleVar());
}
// Check whether the call is actually a require() and translate
// as appropriate.
const require =
maybeCreateGoogRequire(exprStmt, callExpr, newIdent);
if (!require) break;
statements.push(require);
// If this was an export star, split it up into the import (created
// by the maybe call above), and the export operation. This avoids a
// Closure complaint about non-top-level requires.
if (isExportStar) {
const args: ts.Expression[] = [newIdent!];
if (expr.arguments.length > 1) args.push(expr.arguments[1]);
statements.push(ts.createExpressionStatement(
ts.createCall(expr.expression, undefined, args)));
}
return;
}
case ts.SyntaxKind.VariableStatement: {
// It's possibly of the form "var x = require(...);".
const varStmt = node as ts.VariableStatement;
// Verify it's a single decl (and not "var x = ..., y = ...;").
if (varStmt.declarationList.declarations.length !== 1) break;
const decl = varStmt.declarationList.declarations[0];
// Grab the variable name (avoiding things like destructuring
// binds).
if (decl.name.kind !== ts.SyntaxKind.Identifier) break;
if (!decl.initializer || !ts.isCallExpression(decl.initializer)) {
break;
}
const require =
maybeCreateGoogRequire(varStmt, decl.initializer, decl.name);
if (!require) break;
statements.push(require);
return;
}
default:
break;
}
statements.push(node);
}