@@ -77,6 +77,33 @@ function isEsModuleProperty(stmt: ts.ExpressionStatement): boolean {
77
77
return prop . initializer . kind === ts . SyntaxKind . TrueKeyword ;
78
78
}
79
79
80
+ function isHoistedExportAssignment ( stmt : ts . ExpressionStatement ) : boolean {
81
+ function checkVoid0Assignment ( expr : ts . Expression ) : boolean {
82
+ // Ensure this looks something like `exports.abc = exports.xyz = void 0;`.
83
+ if ( ! ts . isBinaryExpression ( expr ) ) return false ;
84
+ if ( expr . operatorToken . kind !== ts . SyntaxKind . EqualsToken ) return false ;
85
+
86
+ // Ensure the left side of the expression is an access on `exports`.
87
+ if ( ! ts . isPropertyAccessExpression ( expr . left ) ) return false ;
88
+ if ( ! ts . isIdentifier ( expr . left . expression ) ) return false ;
89
+ if ( expr . left . expression . escapedText !== 'exports' ) return false ;
90
+
91
+ // If the right side is another `exports.abc = ...` check that to see if we eventually hit a
92
+ // `void 0`.
93
+ if ( ts . isBinaryExpression ( expr . right ) ) {
94
+ return checkVoid0Assignment ( expr . right ) ;
95
+ }
96
+
97
+ // Ensure the right side is exactly "void 0";
98
+ if ( ! ts . isVoidExpression ( expr . right ) ) return false ;
99
+ if ( ! ts . isNumericLiteral ( expr . right . expression ) ) return false ;
100
+ if ( expr . right . expression . text !== '0' ) return false ;
101
+ return true ;
102
+ }
103
+
104
+ return checkVoid0Assignment ( stmt . expression ) ;
105
+ }
106
+
80
107
/**
81
108
* Returns the string argument if call is of the form
82
109
* require('foo')
@@ -467,6 +494,61 @@ export function commonJsToGoogmoduleTransformer(
467
494
return [ require , exportStmt ] ;
468
495
}
469
496
497
+ function rewriteObjectDefinePropertyOnExports ( stmt : ts . ExpressionStatement ) : ts . Statement |
498
+ null {
499
+ if ( ! ts . isCallExpression ( stmt . expression ) ) return null ;
500
+
501
+ const callExpr = stmt . expression ;
502
+ if ( ! ts . isPropertyAccessExpression ( callExpr . expression ) ) return null ;
503
+
504
+ const propAccess = callExpr . expression ;
505
+ if ( ! ts . isIdentifier ( propAccess . expression ) ) return null ;
506
+ if ( propAccess . expression . text !== 'Object' ) return null ;
507
+ if ( propAccess . name . text !== 'defineProperty' ) return null ;
508
+
509
+ const [ objDefArg1 , objDefArg2 , objDefArg3 ] = callExpr . arguments ;
510
+ if ( callExpr . arguments . length !== 3 ) return null ;
511
+ if ( ! ts . isIdentifier ( objDefArg1 ) ) return null ;
512
+ if ( objDefArg1 . text !== 'exports' ) return null ;
513
+ if ( ! ts . isStringLiteral ( objDefArg2 ) ) return null ;
514
+ if ( ! ts . isObjectLiteralExpression ( objDefArg3 ) ) return null ;
515
+
516
+ function findPropConfigFor ( name : string ) {
517
+ return ( p : ts . ObjectLiteralElementLike ) => {
518
+ return ts . isPropertyAssignment ( p ) && ts . isIdentifier ( p . name ) && p . name . text === name ;
519
+ } ;
520
+ }
521
+
522
+ const enumerableConfig = objDefArg3 . properties . find ( findPropConfigFor ( 'enumerable' ) ) ;
523
+ if ( ! enumerableConfig ) return null ;
524
+ if ( ! ts . isPropertyAssignment ( enumerableConfig ) ) return null ;
525
+ if ( enumerableConfig . initializer . kind !== ts . SyntaxKind . TrueKeyword ) return null ;
526
+
527
+ const getConfig = objDefArg3 . properties . find ( findPropConfigFor ( 'get' ) ) ;
528
+ if ( ! getConfig ) return null ;
529
+ if ( ! ts . isPropertyAssignment ( getConfig ) ) return null ;
530
+ if ( ! ts . isFunctionExpression ( getConfig . initializer ) ) return null ;
531
+
532
+ const getterFunc = getConfig . initializer ;
533
+ if ( getterFunc . body . statements . length !== 1 ) return null ;
534
+
535
+ const getterReturn = getterFunc . body . statements [ 0 ] ;
536
+ if ( ! ts . isReturnStatement ( getterReturn ) ) return null ;
537
+
538
+ const realExportValue = getterReturn . expression ;
539
+ if ( ! realExportValue ) return null ;
540
+
541
+ const exportStmt = ts . setOriginalNode (
542
+ ts . setTextRange (
543
+ ts . createExpressionStatement ( ts . createAssignment (
544
+ ts . createPropertyAccess ( ts . createIdentifier ( 'exports' ) , objDefArg2 . text ) ,
545
+ realExportValue ) ) ,
546
+ stmt ) ,
547
+ stmt ) ;
548
+
549
+ return exportStmt ;
550
+ }
551
+
470
552
/**
471
553
* visitTopLevelStatement implements the main CommonJS to goog.module conversion. It visits a
472
554
* SourceFile level statement and adds a (possibly) transformed representation of it into
@@ -498,7 +580,8 @@ export function commonJsToGoogmoduleTransformer(
498
580
case ts . SyntaxKind . ExpressionStatement : {
499
581
const exprStmt = node as ts . ExpressionStatement ;
500
582
// Check for "use strict" and certain Object.defineProperty and skip it if necessary.
501
- if ( isUseStrict ( exprStmt ) || isEsModuleProperty ( exprStmt ) ) {
583
+ if ( isUseStrict ( exprStmt ) || isEsModuleProperty ( exprStmt ) ||
584
+ isHoistedExportAssignment ( exprStmt ) ) {
502
585
stmts . push ( createNotEmittedStatementWithComments ( sf , exprStmt ) ) ;
503
586
return ;
504
587
}
@@ -526,6 +609,11 @@ export function commonJsToGoogmoduleTransformer(
526
609
stmts . push ( ...exportStarAsNs ) ;
527
610
return ;
528
611
}
612
+ const exportFromObjDefProp = rewriteObjectDefinePropertyOnExports ( exprStmt ) ;
613
+ if ( exportFromObjDefProp ) {
614
+ stmts . push ( exportFromObjDefProp ) ;
615
+ return ;
616
+ }
529
617
// Check for:
530
618
// "require('foo');" (a require for its side effects)
531
619
const expr = exprStmt . expression ;
0 commit comments