@@ -544,7 +544,7 @@ export class LuaTransformer {
544544 throw TSTLErrors . InvalidExtensionMetaExtension ( statement ) ;
545545 }
546546
547- if ( ( isExtension || isMetaExtension ) && this . isIdentifierExported ( className ) ) {
547+ if ( ( isExtension || isMetaExtension ) && this . getIdentifierExportScope ( className ) !== undefined ) {
548548 // Cannot export extension classes
549549 throw TSTLErrors . InvalidExportsExtension ( statement ) ;
550550 }
@@ -772,12 +772,13 @@ export class LuaTransformer {
772772 const classVar = this . createLocalOrExportedOrGlobalDeclaration ( className , classTable , statement ) ;
773773 result . push ( ...classVar ) ;
774774
775- if ( this . isIdentifierExported ( className ) ) {
775+ const exportScope = this . getIdentifierExportScope ( className ) ;
776+ if ( exportScope ) {
776777 // local localClassName = ____exports.className
777778 result . push (
778779 tstl . createVariableDeclarationStatement (
779780 localClassName ,
780- this . addExportToIdentifier ( tstl . cloneIdentifier ( className ) )
781+ this . createExportedIdentifier ( tstl . cloneIdentifier ( className ) , exportScope )
781782 )
782783 ) ;
783784 }
@@ -1500,9 +1501,7 @@ export class LuaTransformer {
15001501 : tstl . createTableIndexExpression ( tableExpression , tstl . createNumericLiteral ( index + 1 ) ) ;
15011502 result . push ( ...this . createLocalOrExportedOrGlobalDeclaration ( variableName , expression ) ) ;
15021503 if ( element . initializer ) {
1503- const identifier = this . shouldExportIdentifier ( variableName )
1504- ? this . createExportedIdentifier ( variableName )
1505- : variableName ;
1504+ const identifier = this . addExportToIdentifier ( variableName ) ;
15061505 result . push (
15071506 tstl . createIfStatement (
15081507 tstl . createBinaryExpression (
@@ -1561,57 +1560,23 @@ export class LuaTransformer {
15611560 const nameIdentifier = this . transformIdentifier ( statement . name as ts . Identifier ) ;
15621561
15631562 if ( isFirstDeclaration ) {
1564- const isExported = ( ts . getCombinedModifierFlags ( statement ) & ts . ModifierFlags . Export ) !== 0 ;
1565- if ( isExported && this . currentNamespace ) {
1566- // outerNS.innerNS = {}
1567- const namespaceDeclaration = tstl . createAssignmentStatement (
1568- tstl . createTableIndexExpression (
1569- this . createModuleLocalNameIdentifier ( this . currentNamespace ) ,
1570- tstl . createStringLiteral ( nameIdentifier . text )
1571- ) ,
1572- tstl . createTableExpression ( )
1573- ) ;
1574-
1575- result . push ( namespaceDeclaration ) ;
1576-
1577- if ( hasExports && tsHelper . moduleHasEmittedBody ( statement ) ) {
1578- // local innerNS = outerNS.innerNS
1579- const localDeclaration = this . createHoistableVariableDeclarationStatement (
1580- this . createModuleLocalNameIdentifier ( statement ) ,
1581- tstl . createTableIndexExpression (
1582- this . createModuleLocalNameIdentifier ( this . currentNamespace ) ,
1583- tstl . createStringLiteral ( nameIdentifier . text )
1584- )
1585- ) ;
1586-
1587- result . push ( localDeclaration ) ;
1588- }
1589- } else if ( isExported && ! this . currentNamespace && this . isModule ) {
1590- // exports.NS = {}
1591- const namespaceDeclaration = tstl . createAssignmentStatement (
1592- this . createExportedIdentifier ( nameIdentifier ) ,
1593- tstl . createTableExpression ( )
1594- ) ;
1595-
1596- result . push ( namespaceDeclaration ) ;
1563+ // local NS = {} or exportTable.NS = {}
1564+ const localDeclaration = this . createLocalOrExportedOrGlobalDeclaration (
1565+ nameIdentifier ,
1566+ tstl . createTableExpression ( )
1567+ ) ;
15971568
1598- if ( hasExports && tsHelper . moduleHasEmittedBody ( statement ) ) {
1599- // local NS = exports.NS
1600- const localDeclaration = this . createHoistableVariableDeclarationStatement (
1601- this . createModuleLocalNameIdentifier ( statement ) ,
1602- this . createExportedIdentifier ( tstl . cloneIdentifier ( nameIdentifier , statement . name ) )
1603- ) ;
1569+ result . push ( ...localDeclaration ) ;
16041570
1605- result . push ( localDeclaration ) ;
1606- }
1607- } else {
1608- // local NS = {}
1609- const localDeclaration = this . createLocalOrExportedOrGlobalDeclaration (
1571+ const exportScope = this . getIdentifierExportScope ( nameIdentifier ) ;
1572+ if ( exportScope && hasExports && tsHelper . moduleHasEmittedBody ( statement ) ) {
1573+ // local NS = exportTable.NS
1574+ const localDeclaration = this . createHoistableVariableDeclarationStatement (
16101575 this . createModuleLocalNameIdentifier ( statement ) ,
1611- tstl . createTableExpression ( )
1576+ this . createExportedIdentifier ( nameIdentifier , exportScope )
16121577 ) ;
16131578
1614- result . push ( ... localDeclaration ) ;
1579+ result . push ( localDeclaration ) ;
16151580 }
16161581 }
16171582
@@ -1985,9 +1950,7 @@ export class LuaTransformer {
19851950 statement . name . elements . forEach ( element => {
19861951 if ( ! ts . isOmittedExpression ( element ) && element . initializer ) {
19871952 const variableName = this . transformIdentifier ( element . name as ts . Identifier ) ;
1988- const identifier = this . shouldExportIdentifier ( variableName )
1989- ? this . createExportedIdentifier ( variableName )
1990- : variableName ;
1953+ const identifier = this . addExportToIdentifier ( variableName ) ;
19911954 statements . push (
19921955 tstl . createIfStatement (
19931956 tstl . createBinaryExpression (
@@ -3347,10 +3310,7 @@ export class LuaTransformer {
33473310 properties . push ( tstl . createTableFieldExpression ( expression , name , element ) ) ;
33483311 } else if ( ts . isShorthandPropertyAssignment ( element ) ) {
33493312 const valueSymbol = this . checker . getShorthandAssignmentValueSymbol ( element ) ;
3350- let identifier = this . createShorthandIdentifier ( valueSymbol , element . name ) ;
3351- if ( tstl . isIdentifier ( identifier ) && valueSymbol !== undefined && this . isSymbolExported ( valueSymbol ) ) {
3352- identifier = this . createExportedIdentifier ( identifier ) ;
3353- }
3313+ const identifier = this . createShorthandIdentifier ( valueSymbol , element . name ) ;
33543314 properties . push ( tstl . createTableFieldExpression ( identifier , name , element ) ) ;
33553315 } else if ( ts . isMethodDeclaration ( element ) ) {
33563316 const expression = this . transformFunctionExpression ( element ) ;
@@ -4640,8 +4600,10 @@ export class LuaTransformer {
46404600
46414601 private transformIdentifierExpression ( expression : ts . Identifier ) : tstl . Expression {
46424602 const identifier = this . transformIdentifier ( expression ) ;
4643- if ( this . isIdentifierExported ( identifier ) ) {
4644- return this . createExportedIdentifier ( identifier ) ;
4603+
4604+ const exportScope = this . getIdentifierExportScope ( identifier ) ;
4605+ if ( exportScope ) {
4606+ return this . createExportedIdentifier ( identifier , exportScope ) ;
46454607 }
46464608
46474609 switch ( this . getIdentifierText ( expression ) ) {
@@ -4664,28 +4626,44 @@ export class LuaTransformer {
46644626 return identifier ;
46654627 }
46664628
4667- protected isIdentifierExported ( identifier : tstl . Identifier ) : boolean {
4668- const symbolInfo = identifier . symbolId && this . symbolInfo . get ( identifier . symbolId ) ;
4669- if ( ! symbolInfo ) {
4670- return false ;
4629+ protected getSymbolFromIdentifier ( identifier : tstl . Identifier ) : ts . Symbol | undefined {
4630+ if ( identifier . symbolId !== undefined ) {
4631+ const symbolInfo = this . symbolInfo . get ( identifier . symbolId ) ;
4632+ if ( symbolInfo !== undefined ) {
4633+ return symbolInfo . symbol ;
4634+ }
4635+ }
4636+ return undefined ;
4637+ }
4638+
4639+ protected getIdentifierExportScope ( identifier : tstl . Identifier ) : ts . SourceFile | ts . ModuleDeclaration | undefined {
4640+ const symbol = this . getSymbolFromIdentifier ( identifier ) ;
4641+ if ( ! symbol ) {
4642+ return undefined ;
46714643 }
46724644
4673- return this . isSymbolExported ( symbolInfo . symbol ) ;
4645+ return this . getSymbolExportScope ( symbol ) ;
46744646 }
46754647
46764648 protected isSymbolExported ( symbol : ts . Symbol ) : boolean {
4677- if ( ! this . isModule && ! this . currentNamespace ) {
4649+ if ( tsHelper . getExportedSymbolDeclaration ( symbol ) !== undefined ) {
4650+ return true ;
4651+ } else if ( this . currentSourceFile ) {
4652+ // Symbol may have been exported separately (e.g. 'const foo = "bar"; export { foo }')
4653+ return this . isSymbolExportedFromScope ( symbol , this . currentSourceFile ) ;
4654+ } else {
46784655 return false ;
46794656 }
4657+ }
46804658
4681- const currentScope = this . currentNamespace ? this . currentNamespace : this . currentSourceFile ;
4682- if ( currentScope === undefined ) {
4683- throw TSTLErrors . UndefinedScope ( ) ;
4659+ protected isSymbolExportedFromScope ( symbol : ts . Symbol , scope : ts . SourceFile | ts . ModuleDeclaration ) : boolean {
4660+ if ( ts . isSourceFile ( scope ) && ! tsHelper . isFileModule ( scope ) ) {
4661+ return false ;
46844662 }
46854663
4686- let scopeSymbol = this . checker . getSymbolAtLocation ( currentScope ) ;
4664+ let scopeSymbol = this . checker . getSymbolAtLocation ( scope ) ;
46874665 if ( scopeSymbol === undefined ) {
4688- scopeSymbol = this . checker . getTypeAtLocation ( currentScope ) . getSymbol ( ) ;
4666+ scopeSymbol = this . checker . getTypeAtLocation ( scope ) . getSymbol ( ) ;
46894667 }
46904668
46914669 if ( scopeSymbol === undefined || scopeSymbol . exports === undefined ) {
@@ -4705,25 +4683,43 @@ export class LuaTransformer {
47054683 }
47064684
47074685 protected addExportToIdentifier ( identifier : tstl . Identifier ) : tstl . AssignmentLeftHandSideExpression {
4708- if ( this . isIdentifierExported ( identifier ) ) {
4709- return this . createExportedIdentifier ( identifier ) ;
4686+ const exportScope = this . getIdentifierExportScope ( identifier ) ;
4687+ if ( exportScope ) {
4688+ return this . createExportedIdentifier ( identifier , exportScope ) ;
47104689 }
47114690 return identifier ;
47124691 }
47134692
4714- protected createExportedIdentifier ( identifier : tstl . Identifier ) : tstl . TableIndexExpression {
4715- let exportTable : tstl . Identifier ;
4716- if ( this . currentNamespace !== undefined ) {
4717- if ( this . isUnsafeName ( this . currentNamespace . name . text ) ) {
4718- exportTable = this . createModuleLocalNameIdentifier ( this . currentNamespace ) ;
4719- } else {
4720- exportTable = this . transformIdentifier ( this . currentNamespace . name as ts . Identifier ) ;
4721- }
4722- } else {
4723- exportTable = this . createExportsIdentifier ( ) ;
4693+ protected createExportedIdentifier (
4694+ identifier : tstl . Identifier ,
4695+ exportScope ?: ts . SourceFile | ts . ModuleDeclaration
4696+ ) : tstl . AssignmentLeftHandSideExpression {
4697+ const exportTable =
4698+ exportScope && ts . isModuleDeclaration ( exportScope )
4699+ ? this . createModuleLocalNameIdentifier ( exportScope )
4700+ : this . createExportsIdentifier ( ) ;
4701+ return tstl . createTableIndexExpression ( exportTable , tstl . createStringLiteral ( identifier . text ) ) ;
4702+ }
4703+
4704+ protected getSymbolExportScope ( symbol : ts . Symbol ) : ts . SourceFile | ts . ModuleDeclaration | undefined {
4705+ const exportedDeclaration = tsHelper . getExportedSymbolDeclaration ( symbol ) ;
4706+ if ( ! exportedDeclaration ) {
4707+ return undefined ;
47244708 }
47254709
4726- return tstl . createTableIndexExpression ( exportTable , tstl . createStringLiteral ( identifier . text ) ) ;
4710+ const scope = tsHelper . findFirstNodeAbove (
4711+ exportedDeclaration ,
4712+ ( n ) : n is ts . SourceFile | ts . ModuleDeclaration => ts . isSourceFile ( n ) || ts . isModuleDeclaration ( n )
4713+ ) ;
4714+ if ( ! scope ) {
4715+ return undefined ;
4716+ }
4717+
4718+ if ( ! this . isSymbolExportedFromScope ( symbol , scope ) ) {
4719+ return undefined ;
4720+ }
4721+
4722+ return scope ;
47274723 }
47284724
47294725 protected transformLuaLibFunction (
@@ -4827,17 +4823,6 @@ export class LuaTransformer {
48274823 return filePath . replace ( / \. \/ / g, "" ) . replace ( / \/ / g, "." ) ;
48284824 }
48294825
4830- protected shouldExportIdentifier ( identifier : tstl . Identifier | tstl . Identifier [ ] ) : boolean {
4831- if ( ! this . isModule && ! this . currentNamespace ) {
4832- return false ;
4833- }
4834- if ( Array . isArray ( identifier ) ) {
4835- return identifier . some ( i => this . isIdentifierExported ( i ) ) ;
4836- } else {
4837- return this . isIdentifierExported ( identifier ) ;
4838- }
4839- }
4840-
48414826 protected createSelfIdentifier ( tsOriginal ?: ts . Node ) : tstl . Identifier {
48424827 return tstl . createIdentifier ( "self" , tsOriginal ) ;
48434828 }
@@ -4857,20 +4842,19 @@ export class LuaTransformer {
48574842
48584843 const functionDeclaration = tsOriginal && ts . isFunctionDeclaration ( tsOriginal ) ? tsOriginal : undefined ;
48594844
4860- if ( this . shouldExportIdentifier ( lhs ) ) {
4845+ const identifiers = Array . isArray ( lhs ) ? lhs : [ lhs ] ;
4846+ if ( identifiers . length === 0 ) {
4847+ return [ ] ;
4848+ }
4849+
4850+ const exportScope = this . getIdentifierExportScope ( identifiers [ 0 ] ) ;
4851+ if ( exportScope ) {
48614852 // exported
48624853 if ( ! rhs ) {
48634854 return [ ] ;
4864- } else if ( Array . isArray ( lhs ) ) {
4865- assignment = tstl . createAssignmentStatement (
4866- lhs . map ( i => this . createExportedIdentifier ( i ) ) ,
4867- rhs ,
4868- tsOriginal ,
4869- parent
4870- ) ;
48714855 } else {
48724856 assignment = tstl . createAssignmentStatement (
4873- this . createExportedIdentifier ( lhs ) ,
4857+ identifiers . map ( i => this . createExportedIdentifier ( i , exportScope ) ) ,
48744858 rhs ,
48754859 tsOriginal ,
48764860 parent
@@ -5120,10 +5104,15 @@ export class LuaTransformer {
51205104 name = this . hasUnsafeIdentifierName ( propertyIdentifier ) ? this . createSafeName ( propertyName ) : propertyName ;
51215105 }
51225106
5123- const identifier = this . transformIdentifierExpression ( ts . createIdentifier ( name ) ) ;
5107+ let identifier = this . transformIdentifierExpression ( ts . createIdentifier ( name ) ) ;
51245108 tstl . setNodeOriginal ( identifier , propertyIdentifier ) ;
51255109 if ( valueSymbol !== undefined && tstl . isIdentifier ( identifier ) ) {
51265110 identifier . symbolId = this . symbolIds . get ( valueSymbol ) ;
5111+
5112+ const exportScope = this . getSymbolExportScope ( valueSymbol ) ;
5113+ if ( exportScope ) {
5114+ identifier = this . createExportedIdentifier ( identifier , exportScope ) ;
5115+ }
51275116 }
51285117 return identifier ;
51295118 }
0 commit comments