@@ -86,7 +86,10 @@ import {
86
86
isComputedPropertyName ,
87
87
isDecorator ,
88
88
isElementAccessExpression ,
89
+ isEntityName ,
89
90
isEnumConst ,
91
+ isExportAssignment ,
92
+ isExportDeclaration ,
90
93
isExportOrDefaultModifier ,
91
94
isExportSpecifier ,
92
95
isExpression ,
@@ -96,6 +99,8 @@ import {
96
99
isHeritageClause ,
97
100
isIdentifier ,
98
101
isImportClause ,
102
+ isImportDeclaration ,
103
+ isImportEqualsDeclaration ,
99
104
isImportSpecifier ,
100
105
isInJSFile ,
101
106
isInstantiatedModule ,
@@ -425,13 +430,65 @@ export function transformTypeScript(context: TransformationContext) {
425
430
}
426
431
}
427
432
428
- function visitElidableStatement ( node : ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration ) : VisitResult < Node | undefined > {
433
+ /**
434
+ * Determines whether import/export elision is blocked for this statement.
435
+ *
436
+ * @description
437
+ * We generally block import/export elision if the statement was modified by a `before` custom
438
+ * transform, although we will continue to allow it if the statement hasn't replaced a node of a different kind and
439
+ * as long as the local bindings for the declarations are unchanged.
440
+ */
441
+ function isElisionBlocked ( node : ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration ) {
429
442
const parsed = getParseTreeNode ( node ) ;
430
- if ( parsed !== node ) {
431
- // If the node has been transformed by a `before` transformer, perform no ellision on it
432
- // As the type information we would attempt to lookup to perform ellision is potentially unavailable for the synthesized nodes
433
- // We do not reuse `visitorWorker`, as the ellidable statement syntax kinds are technically unrecognized by the switch-case in `visitTypeScript`,
434
- // and will trigger debug failures when debug verbosity is turned up
443
+ if ( parsed === node || isExportAssignment ( node ) ) {
444
+ return false ;
445
+ }
446
+
447
+ if ( ! parsed || parsed . kind !== node . kind ) {
448
+ // no longer safe to elide as the declaration was replaced with a node of a different kind
449
+ return true ;
450
+ }
451
+
452
+ switch ( node . kind ) {
453
+ case SyntaxKind . ImportDeclaration :
454
+ Debug . assertNode ( parsed , isImportDeclaration ) ;
455
+ if ( node . importClause !== parsed . importClause ) {
456
+ return true ; // no longer safe to elide as the import clause has changed
457
+ }
458
+ if ( node . attributes !== parsed . attributes ) {
459
+ return true ; // no longer safe to elide as the import attributes have changed
460
+ }
461
+ break ;
462
+ case SyntaxKind . ImportEqualsDeclaration :
463
+ Debug . assertNode ( parsed , isImportEqualsDeclaration ) ;
464
+ if ( node . name !== parsed . name ) {
465
+ return true ; // no longer safe to elide as local binding has changed
466
+ }
467
+ if ( node . isTypeOnly !== parsed . isTypeOnly ) {
468
+ return true ; // no longer safe to elide as `type` modifier has changed
469
+ }
470
+ if ( node . moduleReference !== parsed . moduleReference && ( isEntityName ( node . moduleReference ) || isEntityName ( parsed . moduleReference ) ) ) {
471
+ return true ; // no longer safe to elide as EntityName reference has changed.
472
+ }
473
+ break ;
474
+ case SyntaxKind . ExportDeclaration :
475
+ Debug . assertNode ( parsed , isExportDeclaration ) ;
476
+ if ( node . exportClause !== parsed . exportClause ) {
477
+ return true ; // no longer safe to elide as the export clause has changed
478
+ }
479
+ if ( node . attributes !== parsed . attributes ) {
480
+ return true ; // no longer safe to elide as the export attributes have changed
481
+ }
482
+ break ;
483
+ }
484
+
485
+ return false ;
486
+ }
487
+
488
+ function visitElidableStatement ( node : ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration ) : VisitResult < Node | undefined > {
489
+ if ( isElisionBlocked ( node ) ) {
490
+ // We do not reuse `visitorWorker`, as the ellidable statement syntax kinds are technically unrecognized by
491
+ // the switch-case in `visitTypeScript`, and will trigger debug failures when debug verbosity is turned up.
435
492
if ( node . transformFlags & TransformFlags . ContainsTypeScript ) {
436
493
// This node contains TypeScript, so we should visit its children.
437
494
return visitEachChild ( node , visitor , context ) ;
0 commit comments