@@ -291,8 +291,11 @@ export function commonJsToGoogmoduleTransformer(
291
291
292
292
let moduleVarCounter = 1 ;
293
293
/**
294
- * Creates a new unique variable to assign side effect imports into. This allows us to re-use
295
- * the variable later on for other imports of the same namespace.
294
+ * Creates a new unique variable name for holding an imported module. This
295
+ * is used to split places where TS wants to codegen code like:
296
+ * someExpression(require(...));
297
+ * which we then rewrite into
298
+ * var x = require(...); someExpression(x);
296
299
*/
297
300
function nextModuleVar ( ) {
298
301
return `tsickle_module_${ moduleVarCounter ++ } _` ;
@@ -305,23 +308,28 @@ export function commonJsToGoogmoduleTransformer(
305
308
const namespaceToModuleVarName = new Map < string , ts . Identifier > ( ) ;
306
309
307
310
/**
308
- * maybeCreateGoogRequire returns a `goog.require()` call for the given CommonJS `require`
309
- * call. Returns null if `call` is not a CommonJS require.
311
+ * maybeCreateGoogRequire returns a `goog.require()` call for the given
312
+ * CommonJS `require` call. Returns null if `call` is not a CommonJS
313
+ * require.
314
+ *
315
+ * @param newIdent The identifier to assign the result of the goog.require
316
+ * to, or undefined if no assignment is needed.
310
317
*/
311
318
function maybeCreateGoogRequire (
312
- original : ts . Statement , call : ts . CallExpression , newIdent : ts . Identifier ) : ts . Statement |
313
- null {
319
+ original : ts . Statement , call : ts . CallExpression ,
320
+ newIdent : ts . Identifier | undefined ) : ts . Statement | null {
314
321
const importedUrl = extractRequire ( call ) ;
315
322
if ( ! importedUrl ) return null ;
316
323
const imp = importPathToGoogNamespace ( host , sf , importedUrl ) ;
317
324
modulesManifest . addReferencedModule ( sf . fileName , imp . text ) ;
318
- const ident : ts . Identifier | undefined = namespaceToModuleVarName . get ( imp . text ) ;
325
+ const existingImport : ts . Identifier | undefined =
326
+ namespaceToModuleVarName . get ( imp . text ) ;
319
327
let initializer : ts . Expression ;
320
- if ( ! ident ) {
321
- namespaceToModuleVarName . set ( imp . text , newIdent ) ;
328
+ if ( ! existingImport ) {
329
+ if ( newIdent ) namespaceToModuleVarName . set ( imp . text , newIdent ) ;
322
330
initializer = createGoogCall ( 'require' , imp ) ;
323
331
} else {
324
- initializer = ident ;
332
+ initializer = existingImport ;
325
333
}
326
334
327
335
// In JS modules it's recommended that users get a handle on the
@@ -332,18 +340,34 @@ export function commonJsToGoogmoduleTransformer(
332
340
// In a goog.module we just want to access the global `goog` value,
333
341
// so we skip emitting that import as a goog.require.
334
342
// We check the goog module name so that we also catch relative imports.
335
- if ( newIdent . escapedText === 'goog' && imp . text === 'google3.javascript.closure.goog' ) {
343
+ if ( newIdent && newIdent . escapedText === 'goog' &&
344
+ imp . text === 'google3.javascript.closure.goog' ) {
336
345
return createNotEmittedStatementWithComments ( sf , original ) ;
337
346
}
338
347
339
- const varDecl = ts . createVariableDeclaration ( newIdent , /* type */ undefined , initializer ) ;
340
- const newStmt = ts . createVariableStatement (
341
- /* modifiers */ undefined ,
342
- ts . createVariableDeclarationList (
343
- [ varDecl ] ,
344
- // Use 'const' in ES6 mode so Closure properly forwards type aliases.
345
- host . es5Mode ? undefined : ts . NodeFlags . Const ) ) ;
346
- return ts . setOriginalNode ( ts . setTextRange ( newStmt , original ) , original ) ;
348
+ if ( newIdent ) {
349
+ // Create a statement like one of:
350
+ // var foo = goog.require('bar');
351
+ // var foo = existingImport;
352
+ const varDecl = ts . createVariableDeclaration (
353
+ newIdent , /* type */ undefined , initializer ) ;
354
+ const newStmt = ts . createVariableStatement (
355
+ /* modifiers */ undefined ,
356
+ ts . createVariableDeclarationList (
357
+ [ varDecl ] ,
358
+ // Use 'const' in ES6 mode so Closure properly forwards type
359
+ // aliases.
360
+ host . es5Mode ? undefined : ts . NodeFlags . Const ) ) ;
361
+ return ts . setOriginalNode (
362
+ ts . setTextRange ( newStmt , original ) , original ) ;
363
+ } else if ( ! newIdent && ! existingImport ) {
364
+ // Create a statement like:
365
+ // goog.require('bar');
366
+ const newStmt = ts . createExpressionStatement ( initializer ) ;
367
+ return ts . setOriginalNode (
368
+ ts . setTextRange ( newStmt , original ) , original ) ;
369
+ }
370
+ return createNotEmittedStatementWithComments ( sf , original ) ;
347
371
}
348
372
349
373
/**
@@ -526,35 +550,53 @@ export function commonJsToGoogmoduleTransformer(
526
550
stmts . push ( ...exportStarAsNs ) ;
527
551
return ;
528
552
}
529
- // Check for:
530
- // "require('foo');" (a require for its side effects)
553
+
554
+ // The rest of this block handles only some function call forms:
555
+ // goog.declareModuleId(...);
556
+ // require('foo');
557
+ // __exportStar(require('foo'), ...);
531
558
const expr = exprStmt . expression ;
532
559
if ( ! ts . isCallExpression ( expr ) ) break ;
533
560
let callExpr = expr ;
561
+
562
+ // Check for declareModuleId.
534
563
const declaredModuleId = maybeRewriteDeclareModuleId ( exprStmt , callExpr ) ;
535
564
if ( declaredModuleId ) {
536
565
statements . push ( declaredModuleId ) ;
537
566
return ;
538
567
}
539
- // Handle export * in ES5 mode (in ES6 mode, export * is dereferenced already).
540
- // export * creates either a pure top-level '__export(require(...))' or the imported
541
- // version, 'tslib.__exportStar(require(...))'. The imported version is only substituted
542
- // later on though, so appears as a plain "__exportStar" on the top level here.
543
- const isExportStar =
544
- ( ts . isIdentifier ( expr . expression ) && expr . expression . text === '__exportStar' ) ||
545
- ( ts . isIdentifier ( expr . expression ) && expr . expression . text === '__export' ) ;
546
- if ( isExportStar ) callExpr = expr . arguments [ 0 ] as ts . CallExpression ;
547
- const ident = ts . createIdentifier ( nextModuleVar ( ) ) ;
548
- const require = maybeCreateGoogRequire ( exprStmt , callExpr , ident ) ;
568
+
569
+ // Check for __exportStar, the commonjs version of 'export *'.
570
+ // export * creates either a pure top-level '__export(require(...))'
571
+ // or the imported version, 'tslib.__exportStar(require(...))'. The
572
+ // imported version is only substituted later on though, so appears
573
+ // as a plain "__exportStar" on the top level here.
574
+ const isExportStar = ts . isIdentifier ( expr . expression ) &&
575
+ ( expr . expression . text === '__exportStar' ||
576
+ expr . expression . text === '__export' ) ;
577
+ let newIdent : ts . Identifier | undefined ;
578
+ if ( isExportStar ) {
579
+ // Extract the goog.require() from the call. (It will be verified
580
+ // as a goog.require() below.)
581
+ callExpr = expr . arguments [ 0 ] as ts . CallExpression ;
582
+ newIdent = ts . createIdentifier ( nextModuleVar ( ) ) ;
583
+ }
584
+
585
+ // Check whether the call is actually a require() and translate
586
+ // as appropriate.
587
+ const require =
588
+ maybeCreateGoogRequire ( exprStmt , callExpr , newIdent ) ;
549
589
if ( ! require ) break ;
550
590
statements . push ( require ) ;
551
- // If this is an export star, split it up into the import (created by the maybe call
552
- // above), and the export operation. This avoids a Closure complaint about non-top-level
553
- // requires.
591
+
592
+ // If this was an export star, split it up into the import (created
593
+ // by the maybe call above), and the export operation. This avoids a
594
+ // Closure complaint about non-top-level requires.
554
595
if ( isExportStar ) {
555
- const args : ts . Expression [ ] = [ ident ] ;
596
+ const args : ts . Expression [ ] = [ newIdent ! ] ;
556
597
if ( expr . arguments . length > 1 ) args . push ( expr . arguments [ 1 ] ) ;
557
- statements . push ( ts . createStatement ( ts . createCall ( expr . expression , undefined , args ) ) ) ;
598
+ statements . push ( ts . createStatement (
599
+ ts . createCall ( expr . expression , undefined , args ) ) ) ;
558
600
}
559
601
return ;
560
602
}
0 commit comments