1
1
/*@internal */
2
2
namespace ts {
3
+
4
+ const enum ImportOrExportBindingReferenceKind {
5
+ None ,
6
+ ImportedHelper ,
7
+ TopLevelExportBinding ,
8
+ ImportClause ,
9
+ ImportSpecifier ,
10
+ }
11
+
12
+ type ImportOrExportBindingReferenceResult =
13
+ | { kind : ImportOrExportBindingReferenceKind . None , node : undefined }
14
+ | { kind : ImportOrExportBindingReferenceKind . ImportedHelper , node : Identifier }
15
+ | { kind : ImportOrExportBindingReferenceKind . TopLevelExportBinding , node : undefined }
16
+ | { kind : ImportOrExportBindingReferenceKind . ImportClause , node : ImportClause }
17
+ | { kind : ImportOrExportBindingReferenceKind . ImportSpecifier , node : ImportSpecifier } ;
18
+
19
+ const noReferenceResult : ImportOrExportBindingReferenceResult = { kind : ImportOrExportBindingReferenceKind . None , node : undefined } ;
20
+ const topLevelExportReferenceResult : ImportOrExportBindingReferenceResult = { kind : ImportOrExportBindingReferenceKind . TopLevelExportBinding , node : undefined } ;
21
+
3
22
export function transformModule ( context : TransformationContext ) {
4
23
interface AsynchronousDependencies {
5
24
aliasedModuleNames : Expression [ ] ;
@@ -48,6 +67,7 @@ namespace ts {
48
67
let currentModuleInfo : ExternalModuleInfo ; // The ExternalModuleInfo for the current file.
49
68
let noSubstitution : boolean [ ] ; // Set of nodes for which substitution rules should be ignored.
50
69
let needUMDDynamicImportHelper : boolean ;
70
+ let bindingReferenceCache : ESMap < Node , ImportOrExportBindingReferenceResult > | undefined ;
51
71
52
72
return chainBundle ( context , transformSourceFile ) ;
53
73
@@ -1756,24 +1776,70 @@ namespace ts {
1756
1776
return node ;
1757
1777
}
1758
1778
1759
- function substituteCallExpression ( node : CallExpression ) {
1760
- if ( ! isIdentifier ( node . expression ) ) {
1761
- return node ;
1779
+ function getImportOrExportBindingReferenceWorker ( node : Identifier ) : ImportOrExportBindingReferenceResult {
1780
+ if ( getEmitFlags ( node ) & EmitFlags . HelperName ) {
1781
+ const externalHelpersModuleName = getExternalHelpersModuleName ( currentSourceFile ) ;
1782
+ if ( externalHelpersModuleName ) {
1783
+ return { kind : ImportOrExportBindingReferenceKind . ImportedHelper , node : externalHelpersModuleName } ;
1784
+ }
1762
1785
}
1763
- const newExpression = substituteExpressionIdentifier ( node . expression ) ;
1764
- if ( newExpression !== node . expression ) {
1765
- return updateCall ( node , setTextRange ( createBinary ( createNumericLiteral ( "0" ) , SyntaxKind . CommaToken , newExpression ) , node . expression ) , /*typeArguments*/ undefined , node . arguments ) ;
1786
+ else if ( ! ( isGeneratedIdentifier ( node ) && ! ( node . autoGenerateFlags & GeneratedIdentifierFlags . AllowNameSubstitution ) ) && ! isLocalName ( node ) ) {
1787
+ const exportContainer = resolver . getReferencedExportContainer ( node , isExportName ( node ) ) ;
1788
+ if ( exportContainer ?. kind === SyntaxKind . SourceFile ) {
1789
+ return topLevelExportReferenceResult ;
1790
+ }
1791
+ const importDeclaration = resolver . getReferencedImportDeclaration ( node ) ;
1792
+ if ( importDeclaration ) {
1793
+ if ( isImportClause ( importDeclaration ) ) return { kind : ImportOrExportBindingReferenceKind . ImportClause , node : importDeclaration } ;
1794
+ if ( isImportSpecifier ( importDeclaration ) ) return { kind : ImportOrExportBindingReferenceKind . ImportSpecifier , node : importDeclaration } ;
1795
+ }
1796
+ }
1797
+ return noReferenceResult ;
1798
+ }
1799
+
1800
+ function getImportOrExportBindingReference ( node : Identifier , removeEntry : boolean ) : ImportOrExportBindingReferenceResult {
1801
+ bindingReferenceCache ||= new Map ( ) ;
1802
+ let result = bindingReferenceCache . get ( node ) ;
1803
+ if ( ! result ) {
1804
+ result = getImportOrExportBindingReferenceWorker ( node ) ;
1805
+ if ( ! removeEntry ) {
1806
+ switch ( result . kind ) {
1807
+ case ImportOrExportBindingReferenceKind . ImportedHelper :
1808
+ case ImportOrExportBindingReferenceKind . ImportClause :
1809
+ case ImportOrExportBindingReferenceKind . ImportSpecifier :
1810
+ bindingReferenceCache . set ( node , result ) ;
1811
+ }
1812
+ }
1813
+ }
1814
+ else if ( removeEntry ) {
1815
+ bindingReferenceCache . delete ( node ) ;
1816
+ }
1817
+ return result ;
1818
+ }
1819
+
1820
+ function substituteCallExpression ( node : CallExpression ) {
1821
+ if ( isIdentifier ( node . expression ) && getImportOrExportBindingReference ( node . expression , /*removeEntry*/ false ) . kind !== ImportOrExportBindingReferenceKind . None ) {
1822
+ return isCallChain ( node ) ?
1823
+ factory . updateCallChain ( node ,
1824
+ setTextRange ( factory . createComma ( factory . createNumericLiteral ( 0 ) , node . expression ) , node . expression ) ,
1825
+ node . questionDotToken ,
1826
+ /*typeArguments*/ undefined ,
1827
+ node . arguments ) :
1828
+ factory . updateCallExpression ( node ,
1829
+ setTextRange ( factory . createComma ( factory . createNumericLiteral ( 0 ) , node . expression ) , node . expression ) ,
1830
+ /*typeArguments*/ undefined ,
1831
+ node . arguments ) ;
1766
1832
}
1767
1833
return node ;
1768
1834
}
1769
1835
1770
1836
function substituteTaggedTemplateExpression ( node : TaggedTemplateExpression ) {
1771
- if ( ! isIdentifier ( node . tag ) ) {
1772
- return node ;
1773
- }
1774
- const newTag = substituteExpressionIdentifier ( node . tag ) ;
1775
- if ( newTag !== node . tag ) {
1776
- return updateTaggedTemplate ( node , setTextRange ( createBinary ( createNumericLiteral ( "0" ) , SyntaxKind . CommaToken , newTag ) , node . tag ) , /*typeArguments*/ undefined , node . template ) ;
1837
+ if ( isIdentifier ( node . tag ) && getImportOrExportBindingReference ( node . tag , /*removeEntry*/ false ) . kind !== ImportOrExportBindingReferenceKind . None ) {
1838
+ return factory . updateTaggedTemplateExpression (
1839
+ node ,
1840
+ setTextRange ( factory . createComma ( factory . createNumericLiteral ( 0 ) , node . tag ) , node . tag ) ,
1841
+ /*typeArguments*/ undefined ,
1842
+ node . template ) ;
1777
1843
}
1778
1844
return node ;
1779
1845
}
@@ -1785,51 +1851,38 @@ namespace ts {
1785
1851
* @param node The node to substitute.
1786
1852
*/
1787
1853
function substituteExpressionIdentifier ( node : Identifier ) : Expression {
1788
- if ( getEmitFlags ( node ) & EmitFlags . HelperName ) {
1789
- const externalHelpersModuleName = getExternalHelpersModuleName ( currentSourceFile ) ;
1790
- if ( externalHelpersModuleName ) {
1791
- return factory . createPropertyAccessExpression ( externalHelpersModuleName , node ) ;
1792
- }
1793
-
1794
- return node ;
1795
- }
1796
-
1797
- if ( ! ( isGeneratedIdentifier ( node ) && ! ( node . autoGenerateFlags & GeneratedIdentifierFlags . AllowNameSubstitution ) ) && ! isLocalName ( node ) ) {
1798
- const exportContainer = resolver . getReferencedExportContainer ( node , isExportName ( node ) ) ;
1799
- if ( exportContainer && exportContainer . kind === SyntaxKind . SourceFile ) {
1854
+ const result = getImportOrExportBindingReference ( node , /*removeEntry*/ true ) ;
1855
+ switch ( result . kind ) {
1856
+ case ImportOrExportBindingReferenceKind . ImportedHelper :
1857
+ return factory . createPropertyAccessExpression ( result . node , node ) ;
1858
+ case ImportOrExportBindingReferenceKind . TopLevelExportBinding :
1800
1859
return setTextRange (
1801
1860
factory . createPropertyAccessExpression (
1802
1861
factory . createIdentifier ( "exports" ) ,
1803
1862
factory . cloneNode ( node )
1804
1863
) ,
1805
1864
/*location*/ node
1806
1865
) ;
1807
- }
1808
-
1809
- const importDeclaration = resolver . getReferencedImportDeclaration ( node ) ;
1810
- if ( importDeclaration ) {
1811
- if ( isImportClause ( importDeclaration ) ) {
1812
- return setTextRange (
1813
- factory . createPropertyAccessExpression (
1814
- factory . getGeneratedNameForNode ( importDeclaration . parent ) ,
1815
- factory . createIdentifier ( "default" )
1816
- ) ,
1817
- /*location*/ node
1818
- ) ;
1819
- }
1820
- else if ( isImportSpecifier ( importDeclaration ) ) {
1821
- const name = importDeclaration . propertyName || importDeclaration . name ;
1822
- return setTextRange (
1823
- factory . createPropertyAccessExpression (
1824
- factory . getGeneratedNameForNode ( importDeclaration . parent ?. parent ?. parent || importDeclaration ) ,
1825
- factory . cloneNode ( name )
1826
- ) ,
1827
- /*location*/ node
1828
- ) ;
1829
- }
1830
- }
1866
+ case ImportOrExportBindingReferenceKind . ImportClause :
1867
+ return setTextRange (
1868
+ factory . createPropertyAccessExpression (
1869
+ factory . getGeneratedNameForNode ( result . node . parent ) ,
1870
+ factory . createIdentifier ( "default" )
1871
+ ) ,
1872
+ /*location*/ node
1873
+ ) ;
1874
+ case ImportOrExportBindingReferenceKind . ImportSpecifier :
1875
+ const name = result . node . propertyName || result . node . name ;
1876
+ return setTextRange (
1877
+ factory . createPropertyAccessExpression (
1878
+ factory . getGeneratedNameForNode ( result . node . parent ?. parent ?. parent || result . node ) ,
1879
+ factory . cloneNode ( name )
1880
+ ) ,
1881
+ /*location*/ node
1882
+ ) ;
1883
+ default :
1884
+ return node ;
1831
1885
}
1832
- return node ;
1833
1886
}
1834
1887
1835
1888
/**
0 commit comments